@bendyline/docblocks-react 2.7.6 → 2.7.8

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 (43) hide show
  1. package/THIRD_PARTY_NOTICES.txt +205 -35
  2. package/dist/{AiDiagrams-VOCEZS6U.js → AiDiagrams-2IKKSBAU.js} +6 -4
  3. package/dist/{AiEditorAssistant-2MW6UYNI.js → AiEditorAssistant-ANYGVG7P.js} +128 -12
  4. package/dist/AiImagePanel-OXWEFOBC.js +314 -0
  5. package/dist/{AiStudyDialog-DQZVTBI7.js → AiStudyDialog-T3FY74HY.js} +3 -3
  6. package/dist/{AudioExportDialog-EICCBSSE.js → AudioExportDialog-CBMSLQBS.js} +1 -1
  7. package/dist/DocumentConflictDialog-4R4QMKBT.js +217 -0
  8. package/dist/{ExportDialog-LGWBXIWN.js → ExportDialog-FNFD53SY.js} +2 -2
  9. package/dist/{ExportToolbarControls-4LYTXGT3.js → ExportToolbarControls-ZOYH4I36.js} +146 -68
  10. package/dist/{GitUI-F3CNBURE.js → GitUI-3FANM7I3.js} +88 -155
  11. package/dist/{KeyboardShortcutsDialog-HVKDFP5Z.js → KeyboardShortcutsDialog-7XJTDIX2.js} +1 -1
  12. package/dist/{PresentationMaker-T526TBRJ.js → PresentationMaker-COLTVMTS.js} +3 -3
  13. package/dist/{QuickOpenDialog-3QEX7RZG.js → QuickOpenDialog-U2FWCEPA.js} +1 -1
  14. package/dist/{Settings-CfhY489G.d.ts → Settings-ButIB78y.d.ts} +20 -4
  15. package/dist/{ShareDialog-PF7D7ORP.js → ShareDialog-WOWHI6YI.js} +1 -1
  16. package/dist/{SpeechToolbarControl-E6OSJGHL.js → SpeechToolbarControl-BZW6IVZM.js} +1 -1
  17. package/dist/{TextFromNarration-ME6FAYWO.js → TextFromNarration-6BYTUKVZ.js} +2 -2
  18. package/dist/chunk-27E2OON2.js +90 -0
  19. package/dist/{chunk-5O5YTOXG.js → chunk-5YMULR6A.js} +13 -1
  20. package/dist/{chunk-NOYDVL6M.js → chunk-6QHZNL6C.js} +45 -17
  21. package/dist/{chunk-45YTIVYS.js → chunk-A7BK6QFL.js} +363 -26
  22. package/dist/{chunk-PRUEYW3G.js → chunk-BGA5UVKL.js} +58 -17
  23. package/dist/{chunk-T42BH6YX.js → chunk-CXLXGFG2.js} +37 -15
  24. package/dist/{chunk-7CSBRAMT.js → chunk-F7TR5EKX.js} +8 -6
  25. package/dist/chunk-HIKMOKBQ.js +37 -0
  26. package/dist/chunk-OW6JWRAA.js +66 -0
  27. package/dist/{chunk-BNKIPCXO.js → chunk-QXBV3G6T.js} +5 -3
  28. package/dist/{chunk-7HBKKXRV.js → chunk-TN7BY5N3.js} +722 -281
  29. package/dist/{chunk-VJPGZCFS.js → chunk-UYJCL6OW.js} +4 -2
  30. package/dist/{chunk-GFK4TCKN.js → chunk-WDNE5TI3.js} +21 -7
  31. package/dist/{chunk-KBUHWZCF.js → chunk-YX275NPE.js} +1 -1
  32. package/dist/editor.js +3 -3
  33. package/dist/export/index.d.ts +16 -162
  34. package/dist/export/index.js +6 -4
  35. package/dist/image-save-D18dJrUr.d.ts +182 -0
  36. package/dist/index.d.ts +15 -11
  37. package/dist/index.js +1365 -1078
  38. package/dist/{run-export-SPNNH32M.js → run-export-C3PLLWLS.js} +2 -2
  39. package/dist/settings/index.d.ts +1 -1
  40. package/dist/settings/index.js +3 -2
  41. package/package.json +8 -8
  42. package/src/styles/docblocks.css +349 -11
  43. package/dist/DocumentConflictDialog-DZ2BV2IH.js +0 -111
package/dist/index.js CHANGED
@@ -1,9 +1,12 @@
1
+ import {
2
+ createSpeechInputProvider
3
+ } from "./chunk-QXBV3G6T.js";
1
4
  import {
2
5
  ProgressivePlayer
3
6
  } from "./chunk-BZRYQENB.js";
4
7
  import {
5
8
  useConfirmDialog
6
- } from "./chunk-KBUHWZCF.js";
9
+ } from "./chunk-YX275NPE.js";
7
10
  import {
8
11
  BackupIcon,
9
12
  FolderIcon,
@@ -18,9 +21,6 @@ import {
18
21
  SplitViewIcon,
19
22
  WorkspaceIcon
20
23
  } from "./chunk-KHQ44ZFA.js";
21
- import {
22
- createSpeechInputProvider
23
- } from "./chunk-BNKIPCXO.js";
24
24
  import {
25
25
  sharedDocumentFilename
26
26
  } from "./chunk-SPUPWCSI.js";
@@ -51,13 +51,13 @@ import {
51
51
  } from "./chunk-KWG6UP5O.js";
52
52
  import {
53
53
  runExport
54
- } from "./chunk-7CSBRAMT.js";
54
+ } from "./chunk-F7TR5EKX.js";
55
55
  import {
56
56
  createImageSaveOutput
57
57
  } from "./chunk-UONFWKJ7.js";
58
58
  import {
59
59
  buildExportFilename
60
- } from "./chunk-5O5YTOXG.js";
60
+ } from "./chunk-5YMULR6A.js";
61
61
  import {
62
62
  createLocalProofingIgnoreStore
63
63
  } from "./chunk-DUKTAKB4.js";
@@ -71,23 +71,34 @@ import {
71
71
  DEFAULT_WRITE_CANVAS_PREFERENCES,
72
72
  InterfaceFontSettings,
73
73
  ProofingSettingsControls,
74
+ SIDEBAR_COLLAPSE_THRESHOLD,
75
+ SIDEBAR_WIDTH_DEFAULT,
76
+ SIDEBAR_WIDTH_MAX,
77
+ SIDEBAR_WIDTH_MIN,
74
78
  SettingsDialog,
75
79
  ThemeSettings,
76
80
  WRITE_CANVAS_FONT_SCHEMES,
77
81
  WorkspaceSettingsControls,
78
82
  WriteCanvasSettingsControls,
83
+ classifyFormFactor,
84
+ formFactorDataAttributes,
85
+ formatModelSize,
86
+ isInstalledDisplayMode,
79
87
  loadAccentColor,
80
88
  loadInterfaceFont,
81
89
  loadProofingPreferences,
82
90
  loadThemePreference,
83
91
  loadWriteCanvasPreferences,
92
+ resolveLayoutMode,
84
93
  resolveWriteCanvasFonts,
85
94
  saveAccentColor,
86
95
  saveInterfaceFont,
87
96
  saveProofingPreferences,
88
97
  saveThemePreference,
89
- saveWriteCanvasPreferences
90
- } from "./chunk-7HBKKXRV.js";
98
+ saveWriteCanvasPreferences,
99
+ useMediaQuery
100
+ } from "./chunk-TN7BY5N3.js";
101
+ import "./chunk-OW6JWRAA.js";
91
102
  import "./chunk-TBLZBNQF.js";
92
103
  import {
93
104
  FindButton,
@@ -101,17 +112,17 @@ import {
101
112
  matchShortcut,
102
113
  shortcutLabel
103
114
  } from "./chunk-ACQF63SB.js";
104
- import "./chunk-PRUEYW3G.js";
115
+ import "./chunk-BGA5UVKL.js";
105
116
  import {
106
117
  buildIssueReportUrl,
107
118
  displayBuildDate,
108
119
  localDateStamp,
109
120
  openExternalUrl
110
- } from "./chunk-T42BH6YX.js";
121
+ } from "./chunk-CXLXGFG2.js";
111
122
  import "./chunk-K4I3NJFL.js";
112
123
  import {
113
124
  ExportDialog
114
- } from "./chunk-GFK4TCKN.js";
125
+ } from "./chunk-WDNE5TI3.js";
115
126
  import "./chunk-H3BK5MK6.js";
116
127
  import {
117
128
  DEFAULT_OPTIONS,
@@ -120,14 +131,13 @@ import {
120
131
  import {
121
132
  Dialog,
122
133
  dismissTopmostDialog
123
- } from "./chunk-VJPGZCFS.js";
134
+ } from "./chunk-UYJCL6OW.js";
124
135
 
125
136
  // src/FileExplorer/FileExplorer.tsx
126
137
  import { useCallback as useCallback5, useEffect as useEffect5, useMemo, useRef as useRef5, useState as useState4 } from "react";
127
138
  import {
128
139
  isFileSystemMoveStateError,
129
- parseWorkspacePath as parseWorkspacePath4,
130
- tryParseWorkspacePath as tryParseWorkspacePath2
140
+ parseWorkspacePath as parseWorkspacePath4
131
141
  } from "@bendyline/docblocks/filesystem";
132
142
 
133
143
  // src/FileExplorer/useFileTree.ts
@@ -631,6 +641,54 @@ function useFileTree(provider, metadataRefreshKey, metadataRefreshPath) {
631
641
  };
632
642
  }
633
643
 
644
+ // src/FileExplorer/read-issue-text.ts
645
+ import { tryParseWorkspacePath } from "@bendyline/docblocks/filesystem";
646
+ function readIssueText(issue) {
647
+ const failingPath = tryParseWorkspacePath(issue.path);
648
+ if (failingPath && failingPath !== issue.directoryPath) {
649
+ return fileIssueText(issue, failingPath);
650
+ }
651
+ return issue.directoryPath === "" ? workspaceIssueText(issue) : folderIssueText(issue);
652
+ }
653
+ function fileIssueText(issue, path) {
654
+ switch (issue.code) {
655
+ case "not-found":
656
+ return `${path} can't be found.`;
657
+ case "permission-denied":
658
+ return `DocBlocks doesn't have permission to open ${path}.`;
659
+ default:
660
+ return `${path} couldn't be read.`;
661
+ }
662
+ }
663
+ function workspaceIssueText(issue) {
664
+ switch (issue.code) {
665
+ case "not-found":
666
+ return "This workspace's folder can't be found. It may have been moved or deleted.";
667
+ case "permission-denied":
668
+ return "DocBlocks doesn't have permission to open this workspace.";
669
+ case "quota-exceeded":
670
+ return "Your device is out of storage space.";
671
+ case "corrupt":
672
+ return "Some of this workspace's saved data couldn't be read.";
673
+ default:
674
+ return "Your documents couldn't be loaded.";
675
+ }
676
+ }
677
+ function folderIssueText(issue) {
678
+ switch (issue.code) {
679
+ case "not-found":
680
+ return "This folder can't be found.";
681
+ case "permission-denied":
682
+ return "DocBlocks doesn't have permission to open this folder.";
683
+ case "quota-exceeded":
684
+ return "Your device is out of storage space.";
685
+ case "corrupt":
686
+ return "Some of this folder's saved data couldn't be read.";
687
+ default:
688
+ return "This folder couldn't be opened.";
689
+ }
690
+ }
691
+
634
692
  // src/FileExplorer/FileTreeNode.tsx
635
693
  import { useCallback as useCallback3, useState as useState2, useRef as useRef3, useEffect as useEffect3, useLayoutEffect } from "react";
636
694
  import { createPortal } from "react-dom";
@@ -1363,7 +1421,7 @@ import { useCallback as useCallback4, useEffect as useEffect4, useId, useLayoutE
1363
1421
  import { createPortal as createPortal2 } from "react-dom";
1364
1422
 
1365
1423
  // src/DocBlocksShell/pinned-documents.ts
1366
- import { tryParseWorkspacePath } from "@bendyline/docblocks/filesystem";
1424
+ import { tryParseWorkspacePath as tryParseWorkspacePath2 } from "@bendyline/docblocks/filesystem";
1367
1425
  var PINNED_DOCUMENTS_STORAGE_KEY = "docblocks-pinned-documents-v1";
1368
1426
  var MAX_PINNED_DOCUMENTS = 100;
1369
1427
  var MAX_WORKSPACE_ID_LENGTH = 256;
@@ -1381,11 +1439,11 @@ function resolvePinnedDocumentStorage() {
1381
1439
  }
1382
1440
  }
1383
1441
  function pinnedDocumentKey(document2) {
1384
- const path = tryParseWorkspacePath(document2.path);
1442
+ const path = tryParseWorkspacePath2(document2.path);
1385
1443
  return `${document2.workspaceId}\0${path ?? document2.path}`;
1386
1444
  }
1387
1445
  function pinnedDocumentName(document2) {
1388
- const canonical = tryParseWorkspacePath(document2.path);
1446
+ const canonical = tryParseWorkspacePath2(document2.path);
1389
1447
  const path = canonical ?? document2.path;
1390
1448
  return path.slice(path.lastIndexOf("/") + 1);
1391
1449
  }
@@ -1402,7 +1460,7 @@ function parsePinnedDocument(value) {
1402
1460
  if (keys.some((key) => key !== "workspaceId" && key !== "workspaceName" && key !== "path") || typeof record.workspaceId !== "string" || record.workspaceId.length === 0 || record.workspaceId.length > MAX_WORKSPACE_ID_LENGTH || typeof record.workspaceName !== "string" || record.workspaceName.length === 0 || record.workspaceName.length > MAX_WORKSPACE_NAME_LENGTH || typeof record.path !== "string" || record.path.length === 0 || record.path.length > MAX_DOCUMENT_PATH_LENGTH) {
1403
1461
  return null;
1404
1462
  }
1405
- const path = tryParseWorkspacePath(record.path);
1463
+ const path = tryParseWorkspacePath2(record.path);
1406
1464
  if (!path) return null;
1407
1465
  return {
1408
1466
  workspaceId: record.workspaceId,
@@ -1454,8 +1512,8 @@ function removePinnedDocument(documents, target) {
1454
1512
  return documents.filter((document2) => pinnedDocumentKey(document2) !== key);
1455
1513
  }
1456
1514
  function relocatePinnedDocuments(documents, workspaceId, oldPath, newPath) {
1457
- const oldCanonical = tryParseWorkspacePath(oldPath);
1458
- const newCanonical = tryParseWorkspacePath(newPath);
1515
+ const oldCanonical = tryParseWorkspacePath2(oldPath);
1516
+ const newCanonical = tryParseWorkspacePath2(newPath);
1459
1517
  if (!oldCanonical || !newCanonical) return [...documents];
1460
1518
  return parsePinnedDocuments(
1461
1519
  documents.map((document2) => {
@@ -2429,8 +2487,11 @@ function isSupportedImportFile(file) {
2429
2487
  if (mimeType.startsWith("text/") || mimeType.startsWith("image/")) return true;
2430
2488
  return !extension && DIRECT_IMPORT_BASENAMES.has(file.name.toLowerCase());
2431
2489
  }
2490
+ function isEditorMediaMimeType(mimeType) {
2491
+ return /^(?:image|video|audio)\//i.test(mimeType);
2492
+ }
2432
2493
  function isEditorDocumentImportFile(file) {
2433
- if (file.type.toLowerCase().startsWith("image/")) return false;
2494
+ if (isEditorMediaMimeType(file.type)) return false;
2434
2495
  const extension = extensionOfFileName(file.name);
2435
2496
  if (DIRECT_IMPORT_IMAGE_EXTENSIONS.has(extension)) return false;
2436
2497
  return isSupportedImportFile(file);
@@ -2501,10 +2562,6 @@ var NEW_ITEM_HINT_ID = "db-new-item-hint";
2501
2562
  function normalisePath2(path) {
2502
2563
  return parseWorkspacePath4(path);
2503
2564
  }
2504
- function readIssueText(issue) {
2505
- const failingPath = tryParseWorkspacePath2(issue.path);
2506
- return failingPath && failingPath !== issue.directoryPath ? `${failingPath}: ${issue.message}` : issue.message;
2507
- }
2508
2565
  function hasEquivalentPath2(paths, path) {
2509
2566
  const canonical = normalisePath2(path);
2510
2567
  return paths.has(path) || paths.has(canonical) || canonical !== "" && paths.has(`/${canonical}`);
@@ -3759,11 +3816,11 @@ async function prepareHostLifecycle(session, request) {
3759
3816
 
3760
3817
  // src/DocBlocksShell/DocBlocksShell.tsx
3761
3818
  import {
3762
- useState as useState24,
3819
+ useState as useState25,
3763
3820
  useCallback as useCallback19,
3764
- useEffect as useEffect30,
3821
+ useEffect as useEffect31,
3765
3822
  useLayoutEffect as useLayoutEffect4,
3766
- useRef as useRef20,
3823
+ useRef as useRef21,
3767
3824
  useMemo as useMemo6,
3768
3825
  lazy as lazy2,
3769
3826
  Suspense as Suspense2
@@ -3772,7 +3829,7 @@ import {
3772
3829
  DocumentVersionManager
3773
3830
  } from "@bendyline/squisq/versions";
3774
3831
  import {
3775
- FileSystemContentContainer as FileSystemContentContainer2,
3832
+ FileSystemContentContainer as FileSystemContentContainer3,
3776
3833
  createFileMediaProvider,
3777
3834
  decodeUtf8Text,
3778
3835
  FsError as FsError6,
@@ -3793,10 +3850,10 @@ import {
3793
3850
  import { createMediaProviderFromContainer } from "@bendyline/squisq/storage";
3794
3851
  import {
3795
3852
  getDocBlocksHost,
3796
- getHostEnvironment as getHostEnvironment2,
3853
+ getHostEnvironment as getHostEnvironment3,
3797
3854
  hasDocBlocksHost,
3798
- hostSupports as hostSupports2,
3799
- maybeGetDocBlocksHost as maybeGetDocBlocksHost4
3855
+ hostSupports as hostSupports3,
3856
+ maybeGetDocBlocksHost as maybeGetDocBlocksHost5
3800
3857
  } from "@bendyline/docblocks/host";
3801
3858
  import {
3802
3859
  parseSharedDocumentHash
@@ -3810,33 +3867,313 @@ import {
3810
3867
  saveWorkspace as saveWorkspace3,
3811
3868
  touchWorkspace as touchWorkspace2,
3812
3869
  registerTransientWorkspace,
3813
- getTransientWorkspace,
3870
+ getTransientWorkspace as getTransientWorkspace2,
3814
3871
  unregisterTransientWorkspace,
3815
3872
  appendWorkspaceBackup,
3816
3873
  finishWorkspaceBackup
3817
3874
  } from "@bendyline/docblocks/workspace";
3818
3875
 
3819
3876
  // src/AppMenu/AppMenu.tsx
3820
- import { useState as useState8, useCallback as useCallback9, useRef as useRef9, useEffect as useEffect9 } from "react";
3877
+ import { useState as useState9, useCallback as useCallback9, useRef as useRef9, useEffect as useEffect10 } from "react";
3821
3878
  import {
3822
- getHostEnvironment
3879
+ getHostEnvironment as getHostEnvironment2
3823
3880
  } from "@bendyline/docblocks/host";
3824
3881
 
3825
- // src/Settings/SpeechSettings.tsx
3826
- import { useCallback as useCallback7, useEffect as useEffect7, useId as useId2, useRef as useRef7, useState as useState6 } from "react";
3827
-
3828
- // src/Speech/format.ts
3829
- function formatModelSize(bytes) {
3830
- const gigabytes = bytes / 1024 ** 3;
3831
- if (gigabytes >= 0.95) return `${gigabytes.toFixed(1)} GB`;
3832
- return `${Math.max(1, Math.round(bytes / 1024 ** 2))} MB`;
3833
- }
3882
+ // src/Settings/AppSettingsDialog.tsx
3883
+ import { useEffect as useEffect9, useState as useState8 } from "react";
3884
+ import {
3885
+ getHostEnvironment
3886
+ } from "@bendyline/docblocks/host";
3834
3887
 
3835
3888
  // src/Settings/SpeechSettings.tsx
3889
+ import { useId as useId2 } from "react";
3836
3890
  import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
3837
3891
  function readinessSentence(readiness, ready) {
3838
3892
  return readiness.state === "ready" ? ready : readiness.reason ?? "";
3839
3893
  }
3894
+ function DictationSettingsControls({ session }) {
3895
+ const { status, catalog, preferences, update } = session;
3896
+ const error = sectionError(session.failure, "stt");
3897
+ if (!status || !catalog || !preferences) {
3898
+ return /* @__PURE__ */ jsx7(SpeechSectionFallback, { legend: "Dictation", error });
3899
+ }
3900
+ const sttModels = catalog.models.filter((model) => model.kind === "stt");
3901
+ const installedStt = sttModels.filter((model) => model.installed);
3902
+ const appBytes = appModelBytes(sttModels);
3903
+ return /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
3904
+ /* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: "Dictation" }),
3905
+ /* @__PURE__ */ jsxs6("p", { className: "db-settings-hint", children: [
3906
+ "Dictation runs on this computer; your voice never leaves it. Models download only when you choose.",
3907
+ appBytes > 0 ? ` Dictation models are using ${formatModelSize(appBytes)}.` : ""
3908
+ ] }),
3909
+ /* @__PURE__ */ jsx7(SpeechErrorNotice, { error }),
3910
+ /* @__PURE__ */ jsx7("p", { className: "db-settings-hint", role: "status", "aria-live": "polite", children: readinessSentence(status.stt, "Ready. Use the microphone button in the toolbar.") }),
3911
+ installedStt.length > 1 && /* @__PURE__ */ jsxs6("label", { className: "db-settings-select", children: [
3912
+ /* @__PURE__ */ jsx7("span", { className: "db-settings-select-header", children: "Dictation model" }),
3913
+ /* @__PURE__ */ jsxs6(
3914
+ "select",
3915
+ {
3916
+ className: "db-settings-select-input",
3917
+ value: preferences.sttModel ?? "",
3918
+ onChange: (event) => void update({ sttModel: event.currentTarget.value || null }),
3919
+ children: [
3920
+ /* @__PURE__ */ jsx7("option", { value: "", children: "Recommended" }),
3921
+ installedStt.map((model) => /* @__PURE__ */ jsx7("option", { value: model.id, children: model.label }, model.id))
3922
+ ]
3923
+ }
3924
+ )
3925
+ ] }),
3926
+ /* @__PURE__ */ jsx7("ul", { className: "db-settings-speech-models", children: sttModels.map((model) => /* @__PURE__ */ jsx7(SpeechModelRow, { model, session }, model.id)) })
3927
+ ] });
3928
+ }
3929
+ function NarrationSettingsControls({ session }) {
3930
+ const speedId = useId2();
3931
+ const { status, catalog, preferences, previewing, update } = session;
3932
+ const error = sectionError(session.failure, "tts");
3933
+ if (!status || !catalog || !preferences) {
3934
+ return /* @__PURE__ */ jsx7(SpeechSectionFallback, { legend: "Narration", error });
3935
+ }
3936
+ const ttsModel = catalog.models.find((model) => model.kind === "tts") ?? null;
3937
+ const appBytes = ttsModel ? appModelBytes([ttsModel]) : 0;
3938
+ return /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
3939
+ /* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: "Narration" }),
3940
+ /* @__PURE__ */ jsxs6("p", { className: "db-settings-hint", children: [
3941
+ "Narration runs on this computer; your documents never leave it. Voices download only when you choose.",
3942
+ appBytes > 0 ? ` Narration voices are using ${formatModelSize(appBytes)}.` : ""
3943
+ ] }),
3944
+ /* @__PURE__ */ jsx7(SpeechErrorNotice, { error }),
3945
+ ttsModel ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
3946
+ /* @__PURE__ */ jsx7("p", { className: "db-settings-hint", role: "status", "aria-live": "polite", children: readinessSentence(status.tts, "Ready to read documents aloud.") }),
3947
+ /* @__PURE__ */ jsx7("ul", { className: "db-settings-speech-models", children: /* @__PURE__ */ jsx7(SpeechModelRow, { model: ttsModel, session }) })
3948
+ ] }) : /* @__PURE__ */ jsx7("p", { className: "db-settings-hint", children: "Narration is not available on this computer." }),
3949
+ ttsModel?.installed && /* @__PURE__ */ jsxs6(Fragment4, { children: [
3950
+ /* @__PURE__ */ jsxs6("label", { className: "db-settings-select", children: [
3951
+ /* @__PURE__ */ jsx7("span", { className: "db-settings-select-header", children: "Voice" }),
3952
+ /* @__PURE__ */ jsx7(
3953
+ "select",
3954
+ {
3955
+ className: "db-settings-select-input",
3956
+ value: preferences.voice ?? catalog.voices[0]?.id ?? "",
3957
+ onChange: (event) => void update({ voice: event.currentTarget.value }),
3958
+ children: catalog.voices.map((voice) => /* @__PURE__ */ jsxs6("option", { value: voice.id, children: [
3959
+ voice.label,
3960
+ " (",
3961
+ voice.language === "en-GB" ? "UK" : "US",
3962
+ voice.gender ? ` ${voice.gender}` : "",
3963
+ ")"
3964
+ ] }, voice.id))
3965
+ }
3966
+ )
3967
+ ] }),
3968
+ /* @__PURE__ */ jsxs6("label", { className: "db-settings-select", htmlFor: speedId, children: [
3969
+ /* @__PURE__ */ jsxs6("span", { className: "db-settings-select-header", children: [
3970
+ "Speed: ",
3971
+ preferences.speed.toFixed(2),
3972
+ "\xD7"
3973
+ ] }),
3974
+ /* @__PURE__ */ jsx7(
3975
+ "input",
3976
+ {
3977
+ id: speedId,
3978
+ type: "range",
3979
+ min: 0.5,
3980
+ max: 2,
3981
+ step: 0.05,
3982
+ value: preferences.speed,
3983
+ onChange: (event) => session.setSpeedDraft(Number(event.currentTarget.value)),
3984
+ onPointerUp: (event) => void update({ speed: Number(event.currentTarget.value) }),
3985
+ onKeyUp: (event) => void update({ speed: Number(event.currentTarget.value) })
3986
+ }
3987
+ )
3988
+ ] }),
3989
+ /* @__PURE__ */ jsx7(
3990
+ "button",
3991
+ {
3992
+ type: "button",
3993
+ className: "db-settings-action db-settings-action--secondary",
3994
+ onClick: () => previewing ? session.stopPreview() : session.startPreview(),
3995
+ children: previewing ? "Stop preview" : "Preview voice"
3996
+ }
3997
+ )
3998
+ ] })
3999
+ ] });
4000
+ }
4001
+ function SpeechModelRow({
4002
+ model,
4003
+ session
4004
+ }) {
4005
+ const { installing } = session;
4006
+ const busy = installing?.id === model.id;
4007
+ const progress = busy ? installing.progress : null;
4008
+ const percent = progress && progress.totalBytes ? Math.round(progress.receivedBytes / progress.totalBytes * 100) : null;
4009
+ return /* @__PURE__ */ jsxs6("li", { className: "db-settings-speech-model", children: [
4010
+ /* @__PURE__ */ jsxs6("div", { className: "db-settings-speech-model-text", children: [
4011
+ /* @__PURE__ */ jsxs6("span", { className: "db-settings-speech-model-name", children: [
4012
+ model.label,
4013
+ model.recommended ? " (recommended)" : ""
4014
+ ] }),
4015
+ /* @__PURE__ */ jsxs6("span", { className: "db-settings-hint", children: [
4016
+ model.description,
4017
+ " ",
4018
+ formatModelSize(model.downloadBytes),
4019
+ " \xB7",
4020
+ " ",
4021
+ /* @__PURE__ */ jsx7("a", { href: model.licenseUrl, target: "_blank", rel: "noreferrer", children: model.license }),
4022
+ model.source === "shared" ? " \xB7 Available from Gezel, no download needed" : model.sharedStorage ? " \xB7 Shared speech storage" : "",
4023
+ model.updateRequired ? " \xB7 Update required" : ""
4024
+ ] })
4025
+ ] }),
4026
+ busy ? /* @__PURE__ */ jsxs6("div", { className: "db-settings-ai-download-progress", role: "status", children: [
4027
+ /* @__PURE__ */ jsx7(
4028
+ "progress",
4029
+ {
4030
+ max: 100,
4031
+ value: percent ?? void 0,
4032
+ "aria-label": `${model.label} download progress`
4033
+ }
4034
+ ),
4035
+ /* @__PURE__ */ jsx7("span", { children: progress?.phase === "verifying" ? "Verifying\u2026" : percent === null ? "Starting\u2026" : `${percent}%` }),
4036
+ /* @__PURE__ */ jsx7(
4037
+ "button",
4038
+ {
4039
+ type: "button",
4040
+ className: "db-settings-action db-settings-action--secondary",
4041
+ onClick: session.cancelInstall,
4042
+ children: "Cancel"
4043
+ }
4044
+ )
4045
+ ] }) : model.source === "app" ? /* @__PURE__ */ jsx7(
4046
+ "button",
4047
+ {
4048
+ type: "button",
4049
+ className: "db-settings-action db-settings-action--secondary",
4050
+ disabled: installing !== null,
4051
+ onClick: () => void session.remove(model),
4052
+ children: "Remove"
4053
+ }
4054
+ ) : model.installed ? null : /* @__PURE__ */ jsxs6(Fragment4, { children: [
4055
+ /* @__PURE__ */ jsx7(
4056
+ "button",
4057
+ {
4058
+ type: "button",
4059
+ className: "db-settings-action",
4060
+ disabled: installing !== null,
4061
+ onClick: () => void session.install(model),
4062
+ children: model.updateRequired ? "Update" : "Download"
4063
+ }
4064
+ ),
4065
+ model.updateRequired && /* @__PURE__ */ jsx7(
4066
+ "button",
4067
+ {
4068
+ type: "button",
4069
+ className: "db-settings-action db-settings-action--secondary",
4070
+ disabled: installing !== null,
4071
+ onClick: () => void session.remove(model),
4072
+ children: "Remove"
4073
+ }
4074
+ )
4075
+ ] })
4076
+ ] });
4077
+ }
4078
+ function sectionError(failure, kind) {
4079
+ return failure && (failure.kind === void 0 || failure.kind === kind) ? failure.error : null;
4080
+ }
4081
+ function appModelBytes(models) {
4082
+ return models.filter((model) => model.source === "app").reduce((sum, model) => sum + model.downloadBytes, 0);
4083
+ }
4084
+ function SpeechSectionFallback({ legend, error }) {
4085
+ if (!error) return null;
4086
+ return /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
4087
+ /* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: legend }),
4088
+ /* @__PURE__ */ jsx7(SpeechErrorNotice, { error })
4089
+ ] });
4090
+ }
4091
+ function SpeechErrorNotice({ error }) {
4092
+ if (!error) return null;
4093
+ return /* @__PURE__ */ jsx7("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: error.message });
4094
+ }
4095
+
4096
+ // src/Settings/TraySettings.tsx
4097
+ import { useCallback as useCallback7, useEffect as useEffect7, useRef as useRef7, useState as useState6 } from "react";
4098
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
4099
+ function trayPlace(platform) {
4100
+ switch (platform) {
4101
+ case "darwin":
4102
+ return { legend: "Menu bar", label: "Show DocBlocks in the menu bar" };
4103
+ case "win32":
4104
+ return {
4105
+ legend: "Notification area",
4106
+ label: "Show DocBlocks in the notification area"
4107
+ };
4108
+ default:
4109
+ return { legend: "System tray", label: "Show DocBlocks in the system tray" };
4110
+ }
4111
+ }
4112
+ function TraySettingsControls({ menu, platform }) {
4113
+ const [enabled, setEnabled] = useState6(null);
4114
+ const [saving, setSaving] = useState6(false);
4115
+ const [failure, setFailure] = useState6(null);
4116
+ const mounted = useRef7(true);
4117
+ useEffect7(() => {
4118
+ mounted.current = true;
4119
+ const read2 = menu.getTrayEnabled;
4120
+ if (read2) {
4121
+ read2.call(menu).then(
4122
+ (value) => {
4123
+ if (mounted.current) setEnabled(value);
4124
+ },
4125
+ () => {
4126
+ if (mounted.current) setFailure("DocBlocks could not read this setting.");
4127
+ }
4128
+ );
4129
+ }
4130
+ return () => {
4131
+ mounted.current = false;
4132
+ };
4133
+ }, [menu]);
4134
+ const change = useCallback7(
4135
+ async (next) => {
4136
+ const write2 = menu.setTrayEnabled;
4137
+ if (!write2) return;
4138
+ setSaving(true);
4139
+ setFailure(null);
4140
+ setEnabled(next);
4141
+ try {
4142
+ const saved = await write2.call(menu, next);
4143
+ if (mounted.current) setEnabled(saved);
4144
+ } catch {
4145
+ if (mounted.current) {
4146
+ setEnabled(!next);
4147
+ setFailure("DocBlocks could not change this setting. Try again.");
4148
+ }
4149
+ } finally {
4150
+ if (mounted.current) setSaving(false);
4151
+ }
4152
+ },
4153
+ [menu]
4154
+ );
4155
+ const place = trayPlace(platform);
4156
+ return /* @__PURE__ */ jsxs7("fieldset", { className: "db-settings-fieldset", children: [
4157
+ /* @__PURE__ */ jsx8("legend", { className: "db-settings-legend", children: place.legend }),
4158
+ /* @__PURE__ */ jsxs7("label", { className: "db-settings-checkbox", children: [
4159
+ /* @__PURE__ */ jsx8(
4160
+ "input",
4161
+ {
4162
+ type: "checkbox",
4163
+ checked: enabled === true,
4164
+ disabled: enabled === null || saving,
4165
+ onChange: (event) => void change(event.currentTarget.checked)
4166
+ }
4167
+ ),
4168
+ place.label
4169
+ ] }),
4170
+ /* @__PURE__ */ jsx8("p", { className: "db-settings-hint", children: "One click to a new document, a folder, or any document you have pinned." }),
4171
+ failure && /* @__PURE__ */ jsx8("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: failure })
4172
+ ] });
4173
+ }
4174
+
4175
+ // src/Settings/useSpeechSettings.ts
4176
+ import { useCallback as useCallback8, useEffect as useEffect8, useRef as useRef8, useState as useState7 } from "react";
3840
4177
  var PREVIEW_TEXT = "This is how I sound when I read your documents aloud.";
3841
4178
  function unreachable(cause) {
3842
4179
  const detail = cause instanceof Error ? cause.message : void 0;
@@ -3846,37 +4183,36 @@ function unreachable(cause) {
3846
4183
  ...detail ? { detail } : {}
3847
4184
  };
3848
4185
  }
3849
- function SpeechSettingsControls({ speech }) {
3850
- const [status, setStatus] = useState6(null);
3851
- const [catalog, setCatalog] = useState6(null);
3852
- const [preferences, setPreferences] = useState6(null);
3853
- const [installing, setInstalling] = useState6(null);
3854
- const [failure, setFailure] = useState6(null);
3855
- const [previewing, setPreviewing] = useState6(false);
3856
- const mounted = useRef7(true);
3857
- const installHandle = useRef7(null);
3858
- const preview = useRef7(null);
3859
- const dictationModelId = useId2();
3860
- const voiceId = useId2();
3861
- const speedId = useId2();
3862
- const refresh = useCallback7(async () => {
4186
+ function useSpeechSettings(speech) {
4187
+ const [status, setStatus] = useState7(null);
4188
+ const [catalog, setCatalog] = useState7(null);
4189
+ const [preferences, setPreferences] = useState7(null);
4190
+ const [installing, setInstalling] = useState7(null);
4191
+ const [failure, setFailure] = useState7(null);
4192
+ const [previewing, setPreviewing] = useState7(false);
4193
+ const mounted = useRef8(true);
4194
+ const installHandle = useRef8(null);
4195
+ const preview = useRef8(null);
4196
+ const refresh = useCallback8(async () => {
4197
+ if (!speech) return;
3863
4198
  try {
3864
4199
  const [nextStatus, nextCatalog] = await Promise.all([speech.status(), speech.catalog()]);
3865
4200
  if (!mounted.current) return;
3866
4201
  setStatus(nextStatus);
3867
4202
  if (nextCatalog.ok) setCatalog(nextCatalog.value);
3868
- else setFailure(nextCatalog.error);
4203
+ else setFailure({ error: nextCatalog.error });
3869
4204
  } catch (cause) {
3870
- if (mounted.current) setFailure(unreachable(cause));
4205
+ if (mounted.current) setFailure({ error: unreachable(cause) });
3871
4206
  }
3872
4207
  }, [speech]);
3873
- const stopPreview = useCallback7(() => {
4208
+ const stopPreview = useCallback8(() => {
3874
4209
  preview.current?.handle.cancel();
3875
4210
  preview.current?.player.dispose();
3876
4211
  preview.current = null;
3877
4212
  setPreviewing(false);
3878
4213
  }, []);
3879
- useEffect7(() => {
4214
+ useEffect8(() => {
4215
+ if (!speech) return;
3880
4216
  mounted.current = true;
3881
4217
  const unsubscribe = speech.onStatus((next) => {
3882
4218
  if (!mounted.current) return;
@@ -3891,7 +4227,7 @@ function SpeechSettingsControls({ speech }) {
3891
4227
  if (mounted.current) setPreferences(initial);
3892
4228
  },
3893
4229
  (cause) => {
3894
- if (mounted.current) setFailure(unreachable(cause));
4230
+ if (mounted.current) setFailure({ error: unreachable(cause) });
3895
4231
  }
3896
4232
  );
3897
4233
  return () => {
@@ -3902,8 +4238,9 @@ function SpeechSettingsControls({ speech }) {
3902
4238
  unsubscribe();
3903
4239
  };
3904
4240
  }, [refresh, speech]);
3905
- const install = useCallback7(
4241
+ const install = useCallback8(
3906
4242
  async (model) => {
4243
+ if (!speech) return;
3907
4244
  setFailure(null);
3908
4245
  setInstalling({ id: model.id, progress: null });
3909
4246
  const handle = speech.installModel(model.id, (progress) => {
@@ -3913,7 +4250,9 @@ function SpeechSettingsControls({ speech }) {
3913
4250
  try {
3914
4251
  const result = await handle.done;
3915
4252
  if (!mounted.current) return;
3916
- if (!result.ok && result.error.code !== "cancelled") setFailure(result.error);
4253
+ if (!result.ok && result.error.code !== "cancelled") {
4254
+ setFailure({ error: result.error, kind: model.kind });
4255
+ }
3917
4256
  await refresh();
3918
4257
  } finally {
3919
4258
  if (installHandle.current === handle) installHandle.current = null;
@@ -3922,18 +4261,21 @@ function SpeechSettingsControls({ speech }) {
3922
4261
  },
3923
4262
  [refresh, speech]
3924
4263
  );
3925
- const remove = useCallback7(
4264
+ const cancelInstall = useCallback8(() => installHandle.current?.cancel(), []);
4265
+ const remove = useCallback8(
3926
4266
  async (model) => {
4267
+ if (!speech) return;
3927
4268
  setFailure(null);
3928
4269
  const result = await speech.removeModel(model.id);
3929
4270
  if (!mounted.current) return;
3930
- if (!result.ok) setFailure(result.error);
4271
+ if (!result.ok) setFailure({ error: result.error, kind: model.kind });
3931
4272
  await refresh();
3932
4273
  },
3933
4274
  [refresh, speech]
3934
4275
  );
3935
- const update = useCallback7(
4276
+ const update = useCallback8(
3936
4277
  async (patch) => {
4278
+ if (!speech) return;
3937
4279
  try {
3938
4280
  const next = await speech.setPreferences(patch);
3939
4281
  if (mounted.current) setPreferences(next);
@@ -3942,8 +4284,11 @@ function SpeechSettingsControls({ speech }) {
3942
4284
  },
3943
4285
  [speech]
3944
4286
  );
3945
- const startPreview = useCallback7(() => {
3946
- const synthesize = speech.synthesize;
4287
+ const setSpeedDraft = useCallback8((speed) => {
4288
+ setPreferences((current) => current ? { ...current, speed } : current);
4289
+ }, []);
4290
+ const startPreview = useCallback8(() => {
4291
+ const synthesize = speech?.synthesize;
3947
4292
  if (!synthesize) return;
3948
4293
  stopPreview();
3949
4294
  const player = ProgressivePlayer.create(() => void 0);
@@ -3961,271 +4306,241 @@ function SpeechSettingsControls({ speech }) {
3961
4306
  preview.current = { handle, player };
3962
4307
  void handle.done.then((result) => {
3963
4308
  if (!mounted.current || preview.current?.handle !== handle) return;
3964
- if (!result.ok && result.error.code !== "cancelled") setFailure(result.error);
4309
+ if (!result.ok && result.error.code !== "cancelled") {
4310
+ setFailure({ error: result.error, kind: "tts" });
4311
+ }
3965
4312
  setPreviewing(false);
3966
4313
  });
3967
4314
  }, [speech, stopPreview]);
3968
- if (!status || !catalog || !preferences) {
3969
- if (!failure) return null;
3970
- return /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
3971
- /* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: "Speech" }),
3972
- /* @__PURE__ */ jsx7("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: failure.message })
3973
- ] });
4315
+ if (!speech) return null;
4316
+ return {
4317
+ speech,
4318
+ status,
4319
+ catalog,
4320
+ preferences,
4321
+ installing,
4322
+ failure,
4323
+ previewing,
4324
+ install,
4325
+ cancelInstall,
4326
+ remove,
4327
+ update,
4328
+ setSpeedDraft,
4329
+ startPreview,
4330
+ stopPreview
4331
+ };
4332
+ }
4333
+
4334
+ // src/Settings/AppSettingsDialog.tsx
4335
+ import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
4336
+ function formatBytes(bytes) {
4337
+ if (!Number.isFinite(bytes) || bytes < 0) return "\u2014";
4338
+ let value = bytes;
4339
+ let unit = "B";
4340
+ for (const next of ["KB", "MB", "GB", "TB"]) {
4341
+ if (value < 1024) break;
4342
+ value /= 1024;
4343
+ unit = next;
3974
4344
  }
3975
- const sttModels = catalog.models.filter((model) => model.kind === "stt");
3976
- const ttsModel = catalog.models.find((model) => model.kind === "tts") ?? null;
3977
- const installedStt = sttModels.filter((model) => model.installed);
3978
- const appBytes = catalog.models.filter((model) => model.source === "app").reduce((sum, model) => sum + model.downloadBytes, 0);
3979
- const modelRow = (model) => {
3980
- const busy = installing?.id === model.id;
3981
- const progress = busy ? installing.progress : null;
3982
- const percent = progress && progress.totalBytes ? Math.round(progress.receivedBytes / progress.totalBytes * 100) : null;
3983
- return /* @__PURE__ */ jsxs6("li", { className: "db-settings-speech-model", children: [
3984
- /* @__PURE__ */ jsxs6("div", { className: "db-settings-speech-model-text", children: [
3985
- /* @__PURE__ */ jsxs6("span", { className: "db-settings-speech-model-name", children: [
3986
- model.label,
3987
- model.recommended ? " (recommended)" : ""
3988
- ] }),
3989
- /* @__PURE__ */ jsxs6("span", { className: "db-settings-hint", children: [
3990
- model.description,
3991
- " ",
3992
- formatModelSize(model.downloadBytes),
3993
- " \xB7",
3994
- " ",
3995
- /* @__PURE__ */ jsx7("a", { href: model.licenseUrl, target: "_blank", rel: "noreferrer", children: model.license }),
3996
- model.source === "shared" ? " \xB7 Available from Gezel, no download needed" : model.sharedStorage ? " \xB7 Shared speech storage" : "",
3997
- model.updateRequired ? " \xB7 Update required" : ""
3998
- ] })
3999
- ] }),
4000
- busy ? /* @__PURE__ */ jsxs6("div", { className: "db-settings-ai-download-progress", role: "status", children: [
4001
- /* @__PURE__ */ jsx7(
4002
- "progress",
4345
+ return `${value >= 100 || unit === "B" ? Math.round(value) : value.toFixed(1)} ${unit}`;
4346
+ }
4347
+ function AppSettingsDialog({
4348
+ onClose,
4349
+ section,
4350
+ onSectionChange,
4351
+ themePreference,
4352
+ onThemeChange,
4353
+ accentColor,
4354
+ onAccentColorChange,
4355
+ interfaceFont,
4356
+ onInterfaceFontChange,
4357
+ writeCanvasSettings,
4358
+ onWriteCanvasSettingsChange,
4359
+ proofingPreferences,
4360
+ onProofingPreferencesChange,
4361
+ ai,
4362
+ speech,
4363
+ tray,
4364
+ getStorageEstimate,
4365
+ storagePersistent,
4366
+ onKeepBrowserData,
4367
+ requestingPersistentStorage = false,
4368
+ versioningPreference,
4369
+ onVersioningPreferenceChange,
4370
+ onOpenWorkspaceSettings
4371
+ }) {
4372
+ const speechSession = useSpeechSettings(speech);
4373
+ const [storageEstimate, setStorageEstimate] = useState8(null);
4374
+ useEffect9(() => {
4375
+ if (!getStorageEstimate) return;
4376
+ let cancelled = false;
4377
+ getStorageEstimate().then((estimate) => {
4378
+ if (!cancelled) setStorageEstimate(estimate);
4379
+ }).catch(() => {
4380
+ if (!cancelled) setStorageEstimate(null);
4381
+ });
4382
+ return () => {
4383
+ cancelled = true;
4384
+ };
4385
+ }, [getStorageEstimate]);
4386
+ const sections = [
4387
+ {
4388
+ id: "appearance",
4389
+ label: "Appearance",
4390
+ content: /* @__PURE__ */ jsxs8(Fragment5, { children: [
4391
+ /* @__PURE__ */ jsx9(
4392
+ ThemeSettings,
4003
4393
  {
4004
- max: 100,
4005
- value: percent ?? void 0,
4006
- "aria-label": `${model.label} download progress`
4394
+ value: themePreference,
4395
+ onChange: (preference) => onThemeChange?.(preference)
4007
4396
  }
4008
4397
  ),
4009
- /* @__PURE__ */ jsx7("span", { children: progress?.phase === "verifying" ? "Verifying\u2026" : percent === null ? "Starting\u2026" : `${percent}%` }),
4010
- /* @__PURE__ */ jsx7(
4011
- "button",
4398
+ /* @__PURE__ */ jsx9(
4399
+ AccentColorSettings,
4012
4400
  {
4013
- type: "button",
4014
- className: "db-settings-action db-settings-action--secondary",
4015
- onClick: () => installHandle.current?.cancel(),
4016
- children: "Cancel"
4401
+ value: accentColor,
4402
+ onChange: (color) => onAccentColorChange?.(color)
4017
4403
  }
4018
- )
4019
- ] }) : model.source === "app" ? /* @__PURE__ */ jsx7(
4020
- "button",
4021
- {
4022
- type: "button",
4023
- className: "db-settings-action db-settings-action--secondary",
4024
- disabled: installing !== null,
4025
- onClick: () => void remove(model),
4026
- children: "Remove"
4027
- }
4028
- ) : model.installed ? null : /* @__PURE__ */ jsxs6(Fragment4, { children: [
4029
- /* @__PURE__ */ jsx7(
4030
- "button",
4404
+ ),
4405
+ /* @__PURE__ */ jsx9(
4406
+ InterfaceFontSettings,
4031
4407
  {
4032
- type: "button",
4033
- className: "db-settings-action",
4034
- disabled: installing !== null,
4035
- onClick: () => void install(model),
4036
- children: model.updateRequired ? "Update" : "Download"
4408
+ value: interfaceFont,
4409
+ onChange: (font) => onInterfaceFontChange?.(font)
4037
4410
  }
4038
4411
  ),
4039
- model.updateRequired && /* @__PURE__ */ jsx7(
4040
- "button",
4412
+ /* @__PURE__ */ jsx9(
4413
+ WriteCanvasSettingsControls,
4041
4414
  {
4042
- type: "button",
4043
- className: "db-settings-action db-settings-action--secondary",
4044
- disabled: installing !== null,
4045
- onClick: () => void remove(model),
4046
- children: "Remove"
4415
+ value: writeCanvasSettings,
4416
+ onChange: (settings) => onWriteCanvasSettingsChange?.(settings)
4047
4417
  }
4048
- )
4049
- ] })
4050
- ] }, model.id);
4051
- };
4052
- return /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
4053
- /* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: "Speech" }),
4054
- /* @__PURE__ */ jsxs6("p", { className: "db-settings-hint", children: [
4055
- "Dictation and narration run on this computer; your voice and documents never leave it. Models download only when you choose.",
4056
- appBytes > 0 ? ` Speech models are using ${formatModelSize(appBytes)}.` : ""
4057
- ] }),
4058
- failure && /* @__PURE__ */ jsx7("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: failure.message }),
4059
- speech.transcribe && /* @__PURE__ */ jsxs6("section", { className: "db-settings-speech-section", "aria-labelledby": dictationModelId, children: [
4060
- /* @__PURE__ */ jsx7("h4", { className: "db-settings-subheading", id: dictationModelId, children: "Dictation" }),
4061
- /* @__PURE__ */ jsx7("p", { className: "db-settings-hint", role: "status", "aria-live": "polite", children: readinessSentence(status.stt, "Ready. Use the microphone button in the toolbar.") }),
4062
- installedStt.length > 1 && /* @__PURE__ */ jsxs6("label", { className: "db-settings-select", children: [
4063
- /* @__PURE__ */ jsx7("span", { className: "db-settings-select-header", children: "Dictation model" }),
4064
- /* @__PURE__ */ jsxs6(
4065
- "select",
4418
+ ),
4419
+ /* @__PURE__ */ jsx9(
4420
+ ProofingSettingsControls,
4066
4421
  {
4067
- className: "db-settings-select-input",
4068
- value: preferences.sttModel ?? "",
4069
- onChange: (event) => void update({ sttModel: event.currentTarget.value || null }),
4070
- children: [
4071
- /* @__PURE__ */ jsx7("option", { value: "", children: "Recommended" }),
4072
- installedStt.map((model) => /* @__PURE__ */ jsx7("option", { value: model.id, children: model.label }, model.id))
4073
- ]
4422
+ value: proofingPreferences,
4423
+ onChange: (settings) => onProofingPreferencesChange?.(settings)
4074
4424
  }
4075
4425
  )
4076
- ] }),
4077
- /* @__PURE__ */ jsx7("ul", { className: "db-settings-speech-models", children: sttModels.map(modelRow) })
4078
- ] }),
4079
- speech.synthesize && ttsModel && /* @__PURE__ */ jsxs6("section", { className: "db-settings-speech-section", "aria-labelledby": voiceId, children: [
4080
- /* @__PURE__ */ jsx7("h4", { className: "db-settings-subheading", id: voiceId, children: "Narration" }),
4081
- /* @__PURE__ */ jsx7("p", { className: "db-settings-hint", role: "status", "aria-live": "polite", children: readinessSentence(status.tts, "Ready to read documents aloud.") }),
4082
- /* @__PURE__ */ jsx7("ul", { className: "db-settings-speech-models", children: modelRow(ttsModel) }),
4083
- ttsModel.installed && /* @__PURE__ */ jsxs6(Fragment4, { children: [
4084
- /* @__PURE__ */ jsxs6("label", { className: "db-settings-select", children: [
4085
- /* @__PURE__ */ jsx7("span", { className: "db-settings-select-header", children: "Voice" }),
4086
- /* @__PURE__ */ jsx7(
4087
- "select",
4426
+ ] })
4427
+ }
4428
+ ];
4429
+ if (ai) {
4430
+ sections.push({ id: "ai", label: "AI", content: /* @__PURE__ */ jsx9(AiSettingsControls, { ai }) });
4431
+ }
4432
+ if (speechSession?.speech.transcribe) {
4433
+ sections.push({
4434
+ id: "dictation",
4435
+ label: "Dictation",
4436
+ content: /* @__PURE__ */ jsx9(DictationSettingsControls, { session: speechSession })
4437
+ });
4438
+ }
4439
+ if (speechSession?.speech.synthesize) {
4440
+ sections.push({
4441
+ id: "narration",
4442
+ label: "Narration",
4443
+ content: /* @__PURE__ */ jsx9(NarrationSettingsControls, { session: speechSession })
4444
+ });
4445
+ }
4446
+ if (tray || getStorageEstimate || onVersioningPreferenceChange) {
4447
+ sections.push({
4448
+ id: "device",
4449
+ label: "Device integration",
4450
+ content: /* @__PURE__ */ jsxs8(Fragment5, { children: [
4451
+ tray && /* @__PURE__ */ jsx9(TraySettingsControls, { menu: tray, platform: getHostEnvironment()?.platform }),
4452
+ getStorageEstimate && /* @__PURE__ */ jsxs8("fieldset", { className: "db-settings-fieldset", children: [
4453
+ /* @__PURE__ */ jsx9("legend", { className: "db-settings-legend", children: "Storage" }),
4454
+ /* @__PURE__ */ jsx9("p", { className: "db-settings-hint", children: storageEstimate ? `DocBlocks documents and app data are using ${formatBytes(
4455
+ storageEstimate.usage
4456
+ )} of the ${formatBytes(
4457
+ storageEstimate.quota
4458
+ )} this browser allows for the site.` : "Storage usage is not available in this browser." }),
4459
+ storagePersistent !== void 0 && /* @__PURE__ */ jsx9("p", { className: "db-settings-hint", children: storagePersistent ? "Protected from routine browser cleanup on this device." : "Browsers may clear site data under storage pressure unless protection is granted." }),
4460
+ onKeepBrowserData && /* @__PURE__ */ jsx9(
4461
+ "button",
4088
4462
  {
4089
- className: "db-settings-select-input",
4090
- value: preferences.voice ?? catalog.voices[0]?.id ?? "",
4091
- onChange: (event) => void update({ voice: event.currentTarget.value }),
4092
- children: catalog.voices.map((voice) => /* @__PURE__ */ jsxs6("option", { value: voice.id, children: [
4093
- voice.label,
4094
- " (",
4095
- voice.language === "en-GB" ? "UK" : "US",
4096
- voice.gender ? ` ${voice.gender}` : "",
4097
- ")"
4098
- ] }, voice.id))
4463
+ type: "button",
4464
+ className: "db-settings-action",
4465
+ disabled: requestingPersistentStorage,
4466
+ onClick: onKeepBrowserData,
4467
+ children: requestingPersistentStorage ? "Requesting storage protection\u2026" : "Protect data from browser cleanup"
4099
4468
  }
4100
4469
  )
4101
4470
  ] }),
4102
- /* @__PURE__ */ jsxs6("label", { className: "db-settings-select", htmlFor: speedId, children: [
4103
- /* @__PURE__ */ jsxs6("span", { className: "db-settings-select-header", children: [
4104
- "Speed: ",
4105
- preferences.speed.toFixed(2),
4106
- "\xD7"
4471
+ onVersioningPreferenceChange && /* @__PURE__ */ jsxs8("fieldset", { className: "db-settings-fieldset", children: [
4472
+ /* @__PURE__ */ jsx9("legend", { className: "db-settings-legend", children: "Version history" }),
4473
+ /* @__PURE__ */ jsxs8("p", { className: "db-settings-hint", children: [
4474
+ "When on, DocBlocks keeps prior revisions of each document inside a sibling",
4475
+ " ",
4476
+ /* @__PURE__ */ jsx9("code", { children: "<name>_files/.versions/" }),
4477
+ " folder. Individual workspaces can override this default in their own settings."
4107
4478
  ] }),
4108
- /* @__PURE__ */ jsx7(
4109
- "input",
4479
+ /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
4480
+ /* @__PURE__ */ jsx9(
4481
+ "input",
4482
+ {
4483
+ type: "radio",
4484
+ name: "versioning",
4485
+ value: "on",
4486
+ checked: versioningPreference === "on",
4487
+ onChange: () => onVersioningPreferenceChange("on")
4488
+ }
4489
+ ),
4490
+ "On for all workspaces"
4491
+ ] }),
4492
+ /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
4493
+ /* @__PURE__ */ jsx9(
4494
+ "input",
4495
+ {
4496
+ type: "radio",
4497
+ name: "versioning",
4498
+ value: "browser-only",
4499
+ checked: versioningPreference === "browser-only",
4500
+ onChange: () => onVersioningPreferenceChange("browser-only")
4501
+ }
4502
+ ),
4503
+ "On in browser workspaces, off for local folders"
4504
+ ] }),
4505
+ /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
4506
+ /* @__PURE__ */ jsx9(
4507
+ "input",
4508
+ {
4509
+ type: "radio",
4510
+ name: "versioning",
4511
+ value: "off",
4512
+ checked: versioningPreference === "off",
4513
+ onChange: () => onVersioningPreferenceChange("off")
4514
+ }
4515
+ ),
4516
+ "Off for all workspaces"
4517
+ ] }),
4518
+ onOpenWorkspaceSettings && /* @__PURE__ */ jsx9(
4519
+ "button",
4110
4520
  {
4111
- id: speedId,
4112
- type: "range",
4113
- min: 0.5,
4114
- max: 2,
4115
- step: 0.05,
4116
- value: preferences.speed,
4117
- onChange: (event) => setPreferences({ ...preferences, speed: Number(event.currentTarget.value) }),
4118
- onPointerUp: (event) => void update({ speed: Number(event.currentTarget.value) }),
4119
- onKeyUp: (event) => void update({ speed: Number(event.currentTarget.value) })
4521
+ type: "button",
4522
+ className: "db-git-secondary-btn db-settings-link-btn",
4523
+ onClick: onOpenWorkspaceSettings,
4524
+ children: "This workspace\u2019s settings\u2026"
4120
4525
  }
4121
- )
4122
- ] }),
4123
- /* @__PURE__ */ jsx7(
4124
- "button",
4125
- {
4126
- type: "button",
4127
- className: "db-settings-action db-settings-action--secondary",
4128
- onClick: () => previewing ? stopPreview() : startPreview(),
4129
- children: previewing ? "Stop preview" : "Preview voice"
4130
- }
4131
- )
4132
- ] })
4133
- ] })
4134
- ] });
4135
- }
4136
-
4137
- // src/Settings/TraySettings.tsx
4138
- import { useCallback as useCallback8, useEffect as useEffect8, useRef as useRef8, useState as useState7 } from "react";
4139
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
4140
- function trayPlace(platform) {
4141
- switch (platform) {
4142
- case "darwin":
4143
- return { legend: "Menu bar", label: "Show DocBlocks in the menu bar" };
4144
- case "win32":
4145
- return {
4146
- legend: "Notification area",
4147
- label: "Show DocBlocks in the notification area"
4148
- };
4149
- default:
4150
- return { legend: "System tray", label: "Show DocBlocks in the system tray" };
4151
- }
4152
- }
4153
- function TraySettingsControls({ menu, platform }) {
4154
- const [enabled, setEnabled] = useState7(null);
4155
- const [saving, setSaving] = useState7(false);
4156
- const [failure, setFailure] = useState7(null);
4157
- const mounted = useRef8(true);
4158
- useEffect8(() => {
4159
- mounted.current = true;
4160
- const read2 = menu.getTrayEnabled;
4161
- if (read2) {
4162
- read2.call(menu).then(
4163
- (value) => {
4164
- if (mounted.current) setEnabled(value);
4165
- },
4166
- () => {
4167
- if (mounted.current) setFailure("DocBlocks could not read this setting.");
4168
- }
4169
- );
4170
- }
4171
- return () => {
4172
- mounted.current = false;
4173
- };
4174
- }, [menu]);
4175
- const change = useCallback8(
4176
- async (next) => {
4177
- const write2 = menu.setTrayEnabled;
4178
- if (!write2) return;
4179
- setSaving(true);
4180
- setFailure(null);
4181
- setEnabled(next);
4182
- try {
4183
- const saved = await write2.call(menu, next);
4184
- if (mounted.current) setEnabled(saved);
4185
- } catch {
4186
- if (mounted.current) {
4187
- setEnabled(!next);
4188
- setFailure("DocBlocks could not change this setting. Try again.");
4189
- }
4190
- } finally {
4191
- if (mounted.current) setSaving(false);
4192
- }
4193
- },
4194
- [menu]
4195
- );
4196
- const place = trayPlace(platform);
4197
- return /* @__PURE__ */ jsxs7("fieldset", { className: "db-settings-fieldset", children: [
4198
- /* @__PURE__ */ jsx8("legend", { className: "db-settings-legend", children: place.legend }),
4199
- /* @__PURE__ */ jsxs7("label", { className: "db-settings-checkbox", children: [
4200
- /* @__PURE__ */ jsx8(
4201
- "input",
4202
- {
4203
- type: "checkbox",
4204
- checked: enabled === true,
4205
- disabled: enabled === null || saving,
4206
- onChange: (event) => void change(event.currentTarget.checked)
4207
- }
4208
- ),
4209
- place.label
4210
- ] }),
4211
- /* @__PURE__ */ jsx8("p", { className: "db-settings-hint", children: "One click to a new document, a folder, or any document you have pinned." }),
4212
- failure && /* @__PURE__ */ jsx8("p", { className: "db-settings-hint db-settings-ai-error", role: "alert", children: failure })
4213
- ] });
4526
+ )
4527
+ ] })
4528
+ ] })
4529
+ });
4530
+ }
4531
+ return /* @__PURE__ */ jsx9(
4532
+ SettingsDialog,
4533
+ {
4534
+ onClose,
4535
+ sections,
4536
+ section,
4537
+ onSectionChange
4538
+ }
4539
+ );
4214
4540
  }
4215
4541
 
4216
4542
  // src/AppMenu/AppMenu.tsx
4217
- import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
4218
- function formatBytes(bytes) {
4219
- if (!Number.isFinite(bytes) || bytes < 0) return "\u2014";
4220
- let value = bytes;
4221
- let unit = "B";
4222
- for (const next of ["KB", "MB", "GB", "TB"]) {
4223
- if (value < 1024) break;
4224
- value /= 1024;
4225
- unit = next;
4226
- }
4227
- return `${value >= 100 || unit === "B" ? Math.round(value) : value.toFixed(1)} ${unit}`;
4228
- }
4543
+ import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
4229
4544
  var DOCUMENTATION_URL = "https://docblocks.com/docs/";
4230
4545
  var MORE_INFORMATION_URLS = Object.freeze({
4231
4546
  electron: "https://docblocks.com/desktop/",
@@ -4260,33 +4575,24 @@ function AppMenu({
4260
4575
  ai,
4261
4576
  speech,
4262
4577
  tray,
4263
- settingsRequest = 0
4578
+ settingsRequest = 0,
4579
+ settingsRequestSection
4264
4580
  }) {
4265
- const [isOpen, setIsOpen] = useState8(false);
4266
- const [showAbout, setShowAbout] = useState8(false);
4267
- const [showSettings, setShowSettings] = useState8(false);
4268
- useEffect9(() => {
4269
- if (settingsRequest > 0) setShowSettings(true);
4270
- }, [settingsRequest]);
4271
- const [requestingPersistentStorage, setRequestingPersistentStorage] = useState8(false);
4272
- const surface = getHostEnvironment()?.surface ?? "web";
4581
+ const [isOpen, setIsOpen] = useState9(false);
4582
+ const [showAbout, setShowAbout] = useState9(false);
4583
+ const [showSettings, setShowSettings] = useState9(false);
4584
+ const [settingsSection, setSettingsSection] = useState9("appearance");
4585
+ useEffect10(() => {
4586
+ if (settingsRequest <= 0) return;
4587
+ if (settingsRequestSection) setSettingsSection(settingsRequestSection);
4588
+ setShowSettings(true);
4589
+ }, [settingsRequest, settingsRequestSection]);
4590
+ const [requestingPersistentStorage, setRequestingPersistentStorage] = useState9(false);
4591
+ const surface = getHostEnvironment2()?.surface ?? "web";
4273
4592
  const moreInformationUrl = MORE_INFORMATION_URLS[surface] ?? MORE_INFORMATION_URLS.web;
4274
4593
  const containerRef = useRef9(null);
4275
4594
  const { menuRef, triggerRef, handleMenuKeyDown, handleTriggerKeyDown, closeMenu } = useMenuKeyboard(isOpen, setIsOpen);
4276
- const [storageEstimate, setStorageEstimate] = useState8(null);
4277
- useEffect9(() => {
4278
- if (!showSettings || !getStorageEstimate) return;
4279
- let cancelled = false;
4280
- getStorageEstimate().then((estimate) => {
4281
- if (!cancelled) setStorageEstimate(estimate);
4282
- }).catch(() => {
4283
- if (!cancelled) setStorageEstimate(null);
4284
- });
4285
- return () => {
4286
- cancelled = true;
4287
- };
4288
- }, [showSettings, getStorageEstimate]);
4289
- useEffect9(() => {
4595
+ useEffect10(() => {
4290
4596
  if (!isOpen) return;
4291
4597
  function handleOutsideClick(e) {
4292
4598
  if (containerRef.current && !containerRef.current.contains(e.target)) {
@@ -4313,9 +4619,9 @@ function AppMenu({
4313
4619
  setRequestingPersistentStorage(false);
4314
4620
  }
4315
4621
  }, [onKeepBrowserData, requestingPersistentStorage]);
4316
- return /* @__PURE__ */ jsxs8(Fragment5, { children: [
4317
- /* @__PURE__ */ jsxs8("div", { ref: containerRef, className: "db-app-menu", children: [
4318
- /* @__PURE__ */ jsxs8(
4622
+ return /* @__PURE__ */ jsxs9(Fragment6, { children: [
4623
+ /* @__PURE__ */ jsxs9("div", { ref: containerRef, className: "db-app-menu", children: [
4624
+ /* @__PURE__ */ jsxs9(
4319
4625
  "button",
4320
4626
  {
4321
4627
  ref: triggerRef,
@@ -4325,8 +4631,8 @@ function AppMenu({
4325
4631
  "aria-expanded": isOpen,
4326
4632
  "aria-haspopup": "menu",
4327
4633
  children: [
4328
- logoUrl ? /* @__PURE__ */ jsxs8(Fragment5, { children: [
4329
- /* @__PURE__ */ jsx9(
4634
+ logoUrl ? /* @__PURE__ */ jsxs9(Fragment6, { children: [
4635
+ /* @__PURE__ */ jsx10(
4330
4636
  "img",
4331
4637
  {
4332
4638
  src: logoUrl,
@@ -4336,7 +4642,7 @@ function AppMenu({
4336
4642
  height: 242
4337
4643
  }
4338
4644
  ),
4339
- logoDarkUrl && /* @__PURE__ */ jsx9(
4645
+ logoDarkUrl && /* @__PURE__ */ jsx10(
4340
4646
  "img",
4341
4647
  {
4342
4648
  src: logoDarkUrl,
@@ -4346,8 +4652,8 @@ function AppMenu({
4346
4652
  height: 242
4347
4653
  }
4348
4654
  )
4349
- ] }) : /* @__PURE__ */ jsx9("span", { className: "db-app-menu-label", children: "docblocks" }),
4350
- /* @__PURE__ */ jsx9(
4655
+ ] }) : /* @__PURE__ */ jsx10("span", { className: "db-app-menu-label", children: "docblocks" }),
4656
+ /* @__PURE__ */ jsx10(
4351
4657
  "span",
4352
4658
  {
4353
4659
  className: `db-app-menu-caret${isOpen ? " db-app-menu-caret--open" : ""}`,
@@ -4357,7 +4663,7 @@ function AppMenu({
4357
4663
  ]
4358
4664
  }
4359
4665
  ),
4360
- isOpen && /* @__PURE__ */ jsxs8(
4666
+ isOpen && /* @__PURE__ */ jsxs9(
4361
4667
  "div",
4362
4668
  {
4363
4669
  ref: menuRef,
@@ -4365,7 +4671,7 @@ function AppMenu({
4365
4671
  role: "menu",
4366
4672
  onKeyDown: handleMenuKeyDown,
4367
4673
  children: [
4368
- /* @__PURE__ */ jsx9(
4674
+ /* @__PURE__ */ jsx10(
4369
4675
  "button",
4370
4676
  {
4371
4677
  className: "db-app-menu-item",
@@ -4375,7 +4681,7 @@ function AppMenu({
4375
4681
  children: "Settings"
4376
4682
  }
4377
4683
  ),
4378
- onInstallApp && /* @__PURE__ */ jsx9(
4684
+ onInstallApp && /* @__PURE__ */ jsx10(
4379
4685
  "button",
4380
4686
  {
4381
4687
  className: "db-app-menu-item",
@@ -4385,8 +4691,8 @@ function AppMenu({
4385
4691
  children: "Install DocBlocks\u2026"
4386
4692
  }
4387
4693
  ),
4388
- (onDownloadAllWorkspaces || onRestoreBackup || onKeepBrowserData) && /* @__PURE__ */ jsx9("div", { className: "db-app-menu-divider" }),
4389
- onDownloadAllWorkspaces && /* @__PURE__ */ jsx9(
4694
+ (onDownloadAllWorkspaces || onRestoreBackup || onKeepBrowserData) && /* @__PURE__ */ jsx10("div", { className: "db-app-menu-divider" }),
4695
+ onDownloadAllWorkspaces && /* @__PURE__ */ jsx10(
4390
4696
  "button",
4391
4697
  {
4392
4698
  className: "db-app-menu-item",
@@ -4396,7 +4702,7 @@ function AppMenu({
4396
4702
  children: "Back up all workspaces"
4397
4703
  }
4398
4704
  ),
4399
- onRestoreBackup && /* @__PURE__ */ jsx9(
4705
+ onRestoreBackup && /* @__PURE__ */ jsx10(
4400
4706
  "button",
4401
4707
  {
4402
4708
  className: "db-app-menu-item",
@@ -4406,7 +4712,7 @@ function AppMenu({
4406
4712
  children: "Restore backup\u2026"
4407
4713
  }
4408
4714
  ),
4409
- onKeepBrowserData && /* @__PURE__ */ jsx9(
4715
+ onKeepBrowserData && /* @__PURE__ */ jsx10(
4410
4716
  "button",
4411
4717
  {
4412
4718
  className: "db-app-menu-item",
@@ -4416,8 +4722,8 @@ function AppMenu({
4416
4722
  children: "Protect data from browser cleanup"
4417
4723
  }
4418
4724
  ),
4419
- /* @__PURE__ */ jsx9("div", { className: "db-app-menu-divider" }),
4420
- onShowKeyboardShortcuts && /* @__PURE__ */ jsxs8(
4725
+ /* @__PURE__ */ jsx10("div", { className: "db-app-menu-divider" }),
4726
+ onShowKeyboardShortcuts && /* @__PURE__ */ jsxs9(
4421
4727
  "button",
4422
4728
  {
4423
4729
  className: "db-app-menu-item db-app-menu-item--with-shortcut",
@@ -4427,11 +4733,11 @@ function AppMenu({
4427
4733
  onClick: () => handleAction(onShowKeyboardShortcuts),
4428
4734
  children: [
4429
4735
  "Keyboard shortcuts",
4430
- /* @__PURE__ */ jsx9("span", { className: "db-app-menu-shortcut", "aria-hidden": "true", children: "F1" })
4736
+ /* @__PURE__ */ jsx10("span", { className: "db-app-menu-shortcut", "aria-hidden": "true", children: "F1" })
4431
4737
  ]
4432
4738
  }
4433
4739
  ),
4434
- /* @__PURE__ */ jsx9(
4740
+ /* @__PURE__ */ jsx10(
4435
4741
  "a",
4436
4742
  {
4437
4743
  className: "db-app-menu-item",
@@ -4444,7 +4750,7 @@ function AppMenu({
4444
4750
  children: "Documentation"
4445
4751
  }
4446
4752
  ),
4447
- /* @__PURE__ */ jsx9(
4753
+ /* @__PURE__ */ jsx10(
4448
4754
  "button",
4449
4755
  {
4450
4756
  className: "db-app-menu-item",
@@ -4458,157 +4764,69 @@ function AppMenu({
4458
4764
  }
4459
4765
  )
4460
4766
  ] }),
4461
- showSettings && /* @__PURE__ */ jsxs8(SettingsDialog, { onClose: () => setShowSettings(false), children: [
4462
- /* @__PURE__ */ jsx9(
4463
- ThemeSettings,
4464
- {
4465
- value: themePreference,
4466
- onChange: (preference) => onThemeChange?.(preference)
4467
- }
4468
- ),
4469
- /* @__PURE__ */ jsx9(
4470
- AccentColorSettings,
4471
- {
4472
- value: accentColor,
4473
- onChange: (color) => onAccentColorChange?.(color)
4474
- }
4475
- ),
4476
- /* @__PURE__ */ jsx9(
4477
- InterfaceFontSettings,
4478
- {
4479
- value: interfaceFont,
4480
- onChange: (font) => onInterfaceFontChange?.(font)
4481
- }
4482
- ),
4483
- /* @__PURE__ */ jsx9(
4484
- WriteCanvasSettingsControls,
4485
- {
4486
- value: writeCanvasSettings,
4487
- onChange: (settings) => onWriteCanvasSettingsChange?.(settings)
4488
- }
4489
- ),
4490
- /* @__PURE__ */ jsx9(
4491
- ProofingSettingsControls,
4492
- {
4493
- value: proofingPreferences,
4494
- onChange: (settings) => onProofingPreferencesChange?.(settings)
4495
- }
4496
- ),
4497
- ai && /* @__PURE__ */ jsx9(AiSettingsControls, { ai }),
4498
- speech && /* @__PURE__ */ jsx9(SpeechSettingsControls, { speech }),
4499
- tray && /* @__PURE__ */ jsx9(TraySettingsControls, { menu: tray, platform: getHostEnvironment()?.platform }),
4500
- getStorageEstimate && /* @__PURE__ */ jsxs8("fieldset", { className: "db-settings-fieldset", children: [
4501
- /* @__PURE__ */ jsx9("legend", { className: "db-settings-legend", children: "Storage" }),
4502
- /* @__PURE__ */ jsx9("p", { className: "db-settings-hint", children: storageEstimate ? `DocBlocks documents and app data are using ${formatBytes(
4503
- storageEstimate.usage
4504
- )} of the ${formatBytes(
4505
- storageEstimate.quota
4506
- )} this browser allows for the site.` : "Storage usage is not available in this browser." }),
4507
- storagePersistent !== void 0 && /* @__PURE__ */ jsx9("p", { className: "db-settings-hint", children: storagePersistent ? "Protected from routine browser cleanup on this device." : "Browsers may clear site data under storage pressure unless protection is granted." }),
4508
- onKeepBrowserData && /* @__PURE__ */ jsx9(
4509
- "button",
4510
- {
4511
- type: "button",
4512
- className: "db-settings-action",
4513
- disabled: requestingPersistentStorage,
4514
- onClick: () => void handleKeepBrowserDataFromSettings(),
4515
- children: requestingPersistentStorage ? "Requesting storage protection\u2026" : "Protect data from browser cleanup"
4516
- }
4517
- )
4518
- ] }),
4519
- onVersioningPreferenceChange && /* @__PURE__ */ jsxs8("fieldset", { className: "db-settings-fieldset", children: [
4520
- /* @__PURE__ */ jsx9("legend", { className: "db-settings-legend", children: "Version history" }),
4521
- /* @__PURE__ */ jsxs8("p", { className: "db-settings-hint", children: [
4522
- "When on, DocBlocks keeps prior revisions of each document inside a sibling",
4523
- " ",
4524
- /* @__PURE__ */ jsx9("code", { children: "<name>_files/.versions/" }),
4525
- " folder. Individual workspaces can override this default in their own settings."
4526
- ] }),
4527
- /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
4528
- /* @__PURE__ */ jsx9(
4529
- "input",
4530
- {
4531
- type: "radio",
4532
- name: "versioning",
4533
- value: "on",
4534
- checked: versioningPreference === "on",
4535
- onChange: () => onVersioningPreferenceChange("on")
4536
- }
4537
- ),
4538
- "On for all workspaces"
4539
- ] }),
4540
- /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
4541
- /* @__PURE__ */ jsx9(
4542
- "input",
4543
- {
4544
- type: "radio",
4545
- name: "versioning",
4546
- value: "browser-only",
4547
- checked: versioningPreference === "browser-only",
4548
- onChange: () => onVersioningPreferenceChange("browser-only")
4549
- }
4550
- ),
4551
- "On in browser workspaces, off for local folders"
4552
- ] }),
4553
- /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
4554
- /* @__PURE__ */ jsx9(
4555
- "input",
4556
- {
4557
- type: "radio",
4558
- name: "versioning",
4559
- value: "off",
4560
- checked: versioningPreference === "off",
4561
- onChange: () => onVersioningPreferenceChange("off")
4562
- }
4563
- ),
4564
- "Off for all workspaces"
4565
- ] }),
4566
- onOpenWorkspaceSettings && /* @__PURE__ */ jsx9(
4567
- "button",
4568
- {
4569
- type: "button",
4570
- className: "db-git-secondary-btn db-settings-link-btn",
4571
- onClick: () => {
4572
- setShowSettings(false);
4573
- onOpenWorkspaceSettings();
4574
- },
4575
- children: "This workspace\u2019s settings\u2026"
4576
- }
4577
- )
4578
- ] })
4579
- ] }),
4580
- showAbout && /* @__PURE__ */ jsxs8(Dialog, { title: "About DocBlocks", onClose: () => setShowAbout(false), children: [
4581
- /* @__PURE__ */ jsxs8("p", { children: [
4582
- /* @__PURE__ */ jsx9("strong", { children: "DocBlocks" }),
4767
+ showSettings && /* @__PURE__ */ jsx10(
4768
+ AppSettingsDialog,
4769
+ {
4770
+ onClose: () => setShowSettings(false),
4771
+ section: settingsSection,
4772
+ onSectionChange: setSettingsSection,
4773
+ themePreference,
4774
+ onThemeChange,
4775
+ accentColor,
4776
+ onAccentColorChange,
4777
+ interfaceFont,
4778
+ onInterfaceFontChange,
4779
+ writeCanvasSettings,
4780
+ onWriteCanvasSettingsChange,
4781
+ proofingPreferences,
4782
+ onProofingPreferencesChange,
4783
+ ai,
4784
+ speech,
4785
+ tray,
4786
+ getStorageEstimate,
4787
+ storagePersistent,
4788
+ onKeepBrowserData: onKeepBrowserData ? () => void handleKeepBrowserDataFromSettings() : void 0,
4789
+ requestingPersistentStorage,
4790
+ versioningPreference,
4791
+ onVersioningPreferenceChange,
4792
+ onOpenWorkspaceSettings: onOpenWorkspaceSettings ? () => {
4793
+ setShowSettings(false);
4794
+ onOpenWorkspaceSettings();
4795
+ } : void 0
4796
+ }
4797
+ ),
4798
+ showAbout && /* @__PURE__ */ jsxs9(Dialog, { title: "About DocBlocks", onClose: () => setShowAbout(false), children: [
4799
+ /* @__PURE__ */ jsxs9("p", { children: [
4800
+ /* @__PURE__ */ jsx10("strong", { children: "DocBlocks" }),
4583
4801
  " is a local-first Markdown document editor. Your files stay under your control."
4584
4802
  ] }),
4585
- appVersion && /* @__PURE__ */ jsxs8("p", { className: "db-about-version", children: [
4586
- /* @__PURE__ */ jsx9("span", { children: "Version" }),
4587
- /* @__PURE__ */ jsx9("code", { "aria-label": `DocBlocks version ${appVersion}`, children: appVersion })
4803
+ appVersion && /* @__PURE__ */ jsxs9("p", { className: "db-about-version", children: [
4804
+ /* @__PURE__ */ jsx10("span", { children: "Version" }),
4805
+ /* @__PURE__ */ jsx10("code", { "aria-label": `DocBlocks version ${appVersion}`, children: appVersion })
4588
4806
  ] }),
4589
- appBuildDate && /* @__PURE__ */ jsxs8("p", { className: "db-about-version", children: [
4590
- /* @__PURE__ */ jsx9("span", { children: "Build" }),
4591
- /* @__PURE__ */ jsx9("time", { dateTime: appBuildDate, children: displayBuildDate(appBuildDate) })
4807
+ appBuildDate && /* @__PURE__ */ jsxs9("p", { className: "db-about-version", children: [
4808
+ /* @__PURE__ */ jsx10("span", { children: "Build" }),
4809
+ /* @__PURE__ */ jsx10("time", { dateTime: appBuildDate, children: displayBuildDate(appBuildDate) })
4592
4810
  ] }),
4593
- /* @__PURE__ */ jsxs8("p", { children: [
4811
+ /* @__PURE__ */ jsxs9("p", { children: [
4594
4812
  "Built with",
4595
4813
  " ",
4596
- /* @__PURE__ */ jsx9("a", { href: "https://github.com/bendyline/squisq", target: "_blank", rel: "noopener noreferrer", children: "squisq" }),
4814
+ /* @__PURE__ */ jsx10("a", { href: "https://github.com/bendyline/squisq", target: "_blank", rel: "noopener noreferrer", children: "squisq" }),
4597
4815
  " ",
4598
4816
  "by",
4599
4817
  " ",
4600
- /* @__PURE__ */ jsx9("a", { href: "https://bendyline.com", target: "_blank", rel: "noopener noreferrer", children: "Bendyline" }),
4818
+ /* @__PURE__ */ jsx10("a", { href: "https://bendyline.com", target: "_blank", rel: "noopener noreferrer", children: "Bendyline" }),
4601
4819
  "."
4602
4820
  ] }),
4603
- surface === "web" && /* @__PURE__ */ jsxs8("p", { children: [
4821
+ surface === "web" && /* @__PURE__ */ jsxs9("p", { children: [
4604
4822
  "See our free desktop apps at",
4605
4823
  " ",
4606
- /* @__PURE__ */ jsx9("a", { href: MORE_INFORMATION_URLS.electron, target: "_blank", rel: "noopener noreferrer", children: "docblocks.com/desktop" }),
4824
+ /* @__PURE__ */ jsx10("a", { href: MORE_INFORMATION_URLS.electron, target: "_blank", rel: "noopener noreferrer", children: "docblocks.com/desktop" }),
4607
4825
  "."
4608
4826
  ] }),
4609
- /* @__PURE__ */ jsxs8("p", { className: "db-dialog-links", children: [
4610
- /* @__PURE__ */ jsx9("a", { href: moreInformationUrl, target: "_blank", rel: "noopener noreferrer", children: "More information..." }),
4611
- /* @__PURE__ */ jsx9(
4827
+ /* @__PURE__ */ jsxs9("p", { className: "db-dialog-links", children: [
4828
+ /* @__PURE__ */ jsx10("a", { href: moreInformationUrl, target: "_blank", rel: "noopener noreferrer", children: "More information..." }),
4829
+ /* @__PURE__ */ jsx10(
4612
4830
  "a",
4613
4831
  {
4614
4832
  href: "https://github.com/bendyline/docblocks",
@@ -4617,7 +4835,7 @@ function AppMenu({
4617
4835
  children: "GitHub"
4618
4836
  }
4619
4837
  ),
4620
- /* @__PURE__ */ jsx9(
4838
+ /* @__PURE__ */ jsx10(
4621
4839
  "a",
4622
4840
  {
4623
4841
  href: "https://github.com/bendyline/docblocks/releases",
@@ -4626,7 +4844,7 @@ function AppMenu({
4626
4844
  children: "Release notes"
4627
4845
  }
4628
4846
  ),
4629
- /* @__PURE__ */ jsx9(
4847
+ /* @__PURE__ */ jsx10(
4630
4848
  "a",
4631
4849
  {
4632
4850
  href: "https://github.com/bendyline/docblocks/issues",
@@ -4635,7 +4853,7 @@ function AppMenu({
4635
4853
  children: "Support"
4636
4854
  }
4637
4855
  ),
4638
- /* @__PURE__ */ jsx9(
4856
+ /* @__PURE__ */ jsx10(
4639
4857
  "a",
4640
4858
  {
4641
4859
  href: "https://github.com/bendyline/docblocks/blob/main/LICENSE",
@@ -4644,7 +4862,7 @@ function AppMenu({
4644
4862
  children: "License (MIT)"
4645
4863
  }
4646
4864
  ),
4647
- /* @__PURE__ */ jsx9(
4865
+ /* @__PURE__ */ jsx10(
4648
4866
  "a",
4649
4867
  {
4650
4868
  href: "https://github.com/bendyline/docblocks/blob/main/NOTICE.md",
@@ -4712,18 +4930,18 @@ async function restoreBrowserBackup(file) {
4712
4930
  }
4713
4931
 
4714
4932
  // src/WorkspacePicker/WorkspaceSettingsButton.tsx
4715
- import { useState as useState9, useCallback as useCallback10, useRef as useRef10, useEffect as useEffect10 } from "react";
4716
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
4933
+ import { useState as useState10, useCallback as useCallback10, useRef as useRef10, useEffect as useEffect11 } from "react";
4934
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
4717
4935
  function WorkspaceSettingsButton({
4718
4936
  onSettings,
4719
4937
  onRename,
4720
4938
  onDownload,
4721
4939
  onRemove
4722
4940
  }) {
4723
- const [isOpen, setIsOpen] = useState9(false);
4941
+ const [isOpen, setIsOpen] = useState10(false);
4724
4942
  const containerRef = useRef10(null);
4725
4943
  const { menuRef, triggerRef, handleMenuKeyDown, handleTriggerKeyDown, closeMenu } = useMenuKeyboard(isOpen, setIsOpen);
4726
- useEffect10(() => {
4944
+ useEffect11(() => {
4727
4945
  if (!isOpen) return;
4728
4946
  function handleOutsideClick(e) {
4729
4947
  if (containerRef.current && !containerRef.current.contains(e.target)) {
@@ -4740,8 +4958,8 @@ function WorkspaceSettingsButton({
4740
4958
  },
4741
4959
  [closeMenu]
4742
4960
  );
4743
- return /* @__PURE__ */ jsxs9("div", { ref: containerRef, className: "db-ws-settings", children: [
4744
- /* @__PURE__ */ jsx10(
4961
+ return /* @__PURE__ */ jsxs10("div", { ref: containerRef, className: "db-ws-settings", children: [
4962
+ /* @__PURE__ */ jsx11(
4745
4963
  "button",
4746
4964
  {
4747
4965
  ref: triggerRef,
@@ -4752,10 +4970,10 @@ function WorkspaceSettingsButton({
4752
4970
  "aria-haspopup": "menu",
4753
4971
  "aria-label": "Workspace settings",
4754
4972
  title: "Workspace settings",
4755
- children: /* @__PURE__ */ jsx10(WorkspaceIcon, {})
4973
+ children: /* @__PURE__ */ jsx11(WorkspaceIcon, {})
4756
4974
  }
4757
4975
  ),
4758
- isOpen && /* @__PURE__ */ jsxs9(
4976
+ isOpen && /* @__PURE__ */ jsxs10(
4759
4977
  "div",
4760
4978
  {
4761
4979
  ref: menuRef,
@@ -4763,7 +4981,7 @@ function WorkspaceSettingsButton({
4763
4981
  role: "menu",
4764
4982
  onKeyDown: handleMenuKeyDown,
4765
4983
  children: [
4766
- /* @__PURE__ */ jsx10(
4984
+ /* @__PURE__ */ jsx11(
4767
4985
  "button",
4768
4986
  {
4769
4987
  className: "db-ws-settings-item",
@@ -4773,7 +4991,7 @@ function WorkspaceSettingsButton({
4773
4991
  children: "Workspace settings\u2026"
4774
4992
  }
4775
4993
  ),
4776
- /* @__PURE__ */ jsx10(
4994
+ /* @__PURE__ */ jsx11(
4777
4995
  "button",
4778
4996
  {
4779
4997
  className: "db-ws-settings-item",
@@ -4783,7 +5001,7 @@ function WorkspaceSettingsButton({
4783
5001
  children: "Rename workspace"
4784
5002
  }
4785
5003
  ),
4786
- /* @__PURE__ */ jsx10(
5004
+ /* @__PURE__ */ jsx11(
4787
5005
  "button",
4788
5006
  {
4789
5007
  className: "db-ws-settings-item",
@@ -4793,8 +5011,8 @@ function WorkspaceSettingsButton({
4793
5011
  children: "Back up this workspace"
4794
5012
  }
4795
5013
  ),
4796
- /* @__PURE__ */ jsx10("div", { className: "db-ws-settings-divider" }),
4797
- /* @__PURE__ */ jsx10(
5014
+ /* @__PURE__ */ jsx11("div", { className: "db-ws-settings-divider" }),
5015
+ /* @__PURE__ */ jsx11(
4798
5016
  "button",
4799
5017
  {
4800
5018
  className: "db-ws-settings-item db-ws-settings-item--danger",
@@ -4811,7 +5029,7 @@ function WorkspaceSettingsButton({
4811
5029
  }
4812
5030
 
4813
5031
  // src/WorkspacePicker/WorkspaceSettingsDialog.tsx
4814
- import { useEffect as useEffect11, useMemo as useMemo2, useState as useState10 } from "react";
5032
+ import { useEffect as useEffect12, useMemo as useMemo2, useState as useState11 } from "react";
4815
5033
  import { getThemeSummaries } from "@bendyline/squisq/schemas";
4816
5034
  import {
4817
5035
  diffWorkspaceSettings,
@@ -4865,7 +5083,7 @@ function resolveVersioningEnabled(workspace, globalPref, workspaceSettings) {
4865
5083
  }
4866
5084
 
4867
5085
  // src/WorkspacePicker/WorkspaceSettingsDialog.tsx
4868
- import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
5086
+ import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
4869
5087
  var VERSIONING_LABELS = {
4870
5088
  on: "on",
4871
5089
  "browser-only": "on for browser workspaces, off for local folders",
@@ -4914,15 +5132,15 @@ function WorkspaceSettingsDialog({
4914
5132
  }) {
4915
5133
  const writable = isWorkspaceSettingsWritable(settings);
4916
5134
  const base = settings.settings;
4917
- const [draft, setDraft] = useState10(
5135
+ const [draft, setDraft] = useState11(
4918
5136
  () => initialDraft(workspace, settings.settings)
4919
5137
  );
4920
- const [touched, setTouched] = useState10(false);
4921
- useEffect11(() => {
5138
+ const [touched, setTouched] = useState11(false);
5139
+ useEffect12(() => {
4922
5140
  if (!touched) setDraft(initialDraft(workspace, settings.settings));
4923
5141
  }, [settings.settings, touched, workspace]);
4924
- const [saving, setSaving] = useState10(false);
4925
- const [saveError, setSaveError] = useState10(null);
5142
+ const [saving, setSaving] = useState11(false);
5143
+ const [saveError, setSaveError] = useState11(null);
4926
5144
  const themes = useMemo2(() => getThemeSummaries(), []);
4927
5145
  const patch = useMemo2(() => diffWorkspaceSettings(base, draft), [base, draft]);
4928
5146
  const validation = useMemo2(() => tryApplyWorkspaceSettingsPatch(base, patch), [base, patch]);
@@ -4947,16 +5165,16 @@ function WorkspaceSettingsDialog({
4947
5165
  }
4948
5166
  };
4949
5167
  const notice = settings.status === "loading" ? "Loading workspace settings\u2026" : writable ? null : settings.message ?? "These workspace settings cannot be changed here.";
4950
- return /* @__PURE__ */ jsxs10(
5168
+ return /* @__PURE__ */ jsxs11(
4951
5169
  Dialog,
4952
5170
  {
4953
5171
  title: "Workspace settings",
4954
5172
  size: "wide",
4955
5173
  onClose,
4956
5174
  closeOnBackdrop: !changed,
4957
- footer: writable ? /* @__PURE__ */ jsxs10(Fragment6, { children: [
4958
- /* @__PURE__ */ jsx11("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Cancel" }),
4959
- /* @__PURE__ */ jsx11(
5175
+ footer: writable ? /* @__PURE__ */ jsxs11(Fragment7, { children: [
5176
+ /* @__PURE__ */ jsx12("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Cancel" }),
5177
+ /* @__PURE__ */ jsx12(
4960
5178
  "button",
4961
5179
  {
4962
5180
  type: "button",
@@ -4966,19 +5184,19 @@ function WorkspaceSettingsDialog({
4966
5184
  children: saving ? "Saving\u2026" : "Save"
4967
5185
  }
4968
5186
  )
4969
- ] }) : /* @__PURE__ */ jsx11("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Close" }),
5187
+ ] }) : /* @__PURE__ */ jsx12("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Close" }),
4970
5188
  children: [
4971
- /* @__PURE__ */ jsxs10("p", { className: "db-settings-hint", children: [
4972
- /* @__PURE__ */ jsx11("strong", { children: workspace.name }),
5189
+ /* @__PURE__ */ jsxs11("p", { className: "db-settings-hint", children: [
5190
+ /* @__PURE__ */ jsx12("strong", { children: workspace.name }),
4973
5191
  " \xB7",
4974
5192
  " ",
4975
5193
  isLocal ? "Local folder workspace" : "Browser workspace",
4976
5194
  " \xB7 saved in",
4977
5195
  " ",
4978
- /* @__PURE__ */ jsx11("code", { children: ".docblocks/workspace.json" })
5196
+ /* @__PURE__ */ jsx12("code", { children: ".docblocks/workspace.json" })
4979
5197
  ] }),
4980
- notice && /* @__PURE__ */ jsx11("p", { className: "db-settings-status db-settings-status--warning", role: "status", children: notice }),
4981
- /* @__PURE__ */ jsx11(
5198
+ notice && /* @__PURE__ */ jsx12("p", { className: "db-settings-status db-settings-status--warning", role: "status", children: notice }),
5199
+ /* @__PURE__ */ jsx12(
4982
5200
  WorkspaceSettingsControls,
4983
5201
  {
4984
5202
  value: draft,
@@ -4995,14 +5213,14 @@ function WorkspaceSettingsDialog({
4995
5213
  regenerating: outputsStatus.state === "running"
4996
5214
  }
4997
5215
  ),
4998
- (saveError || !validation.ok && changed) && /* @__PURE__ */ jsx11("p", { className: "db-settings-status db-settings-status--warning", role: "alert", children: saveError ?? (!validation.ok ? validation.message : null) })
5216
+ (saveError || !validation.ok && changed) && /* @__PURE__ */ jsx12("p", { className: "db-settings-status db-settings-status--warning", role: "alert", children: saveError ?? (!validation.ok ? validation.message : null) })
4999
5217
  ]
5000
5218
  }
5001
5219
  );
5002
5220
  }
5003
5221
 
5004
5222
  // src/WorkspaceSettings/useWorkspaceSettings.ts
5005
- import { useCallback as useCallback11, useEffect as useEffect12, useRef as useRef11, useState as useState11 } from "react";
5223
+ import { useCallback as useCallback11, useEffect as useEffect13, useRef as useRef11, useState as useState12 } from "react";
5006
5224
  import { maybeGetDocBlocksHost } from "@bendyline/docblocks/host";
5007
5225
  import { getFileSystemProviderV2 as getFileSystemProviderV24 } from "@bendyline/docblocks/filesystem";
5008
5226
  import {
@@ -5017,13 +5235,13 @@ function sameState(left, right) {
5017
5235
  }
5018
5236
  function useWorkspaceSettings(provider, enabled) {
5019
5237
  const providerV2 = provider && enabled ? getFileSystemProviderV24(provider) : null;
5020
- const [state, setState] = useState11(
5238
+ const [state, setState] = useState12(
5021
5239
  providerV2 ? LOADING_WORKSPACE_SETTINGS : UNAVAILABLE_WORKSPACE_SETTINGS
5022
5240
  );
5023
5241
  const stateRef = useRef11(state);
5024
5242
  stateRef.current = state;
5025
5243
  const generationRef = useRef11(0);
5026
- const [refreshKey, setRefreshKey] = useState11(0);
5244
+ const [refreshKey, setRefreshKey] = useState12(0);
5027
5245
  const refresh = useCallback11(() => setRefreshKey((key) => key + 1), []);
5028
5246
  const providerRef = useRef11(providerV2);
5029
5247
  if (providerRef.current !== providerV2) {
@@ -5033,7 +5251,7 @@ function useWorkspaceSettings(provider, enabled) {
5033
5251
  stateRef.current = reset;
5034
5252
  setState(reset);
5035
5253
  }
5036
- useEffect12(() => {
5254
+ useEffect13(() => {
5037
5255
  if (!providerV2) return;
5038
5256
  const generation = generationRef.current;
5039
5257
  let cancelled = false;
@@ -5048,7 +5266,7 @@ function useWorkspaceSettings(provider, enabled) {
5048
5266
  cancelled = true;
5049
5267
  };
5050
5268
  }, [providerV2, refreshKey]);
5051
- useEffect12(() => {
5269
+ useEffect13(() => {
5052
5270
  if (!providerV2) return;
5053
5271
  window.addEventListener("focus", refresh);
5054
5272
  const stopResume = maybeGetDocBlocksHost()?.lifecycle?.onResume?.(refresh);
@@ -5084,7 +5302,7 @@ function useWorkspaceSettings(provider, enabled) {
5084
5302
  }
5085
5303
 
5086
5304
  // src/WorkspaceSettings/useWorkspaceOutputs.ts
5087
- import { useEffect as useEffect13, useState as useState12, useSyncExternalStore as useSyncExternalStore2 } from "react";
5305
+ import { useEffect as useEffect14, useState as useState13, useSyncExternalStore as useSyncExternalStore2 } from "react";
5088
5306
  import { getFileSystemProviderV2 as getFileSystemProviderV25 } from "@bendyline/docblocks/filesystem";
5089
5307
  import {
5090
5308
  createWorkspaceOutputsScheduler,
@@ -5108,8 +5326,8 @@ var noSubscription = () => () => void 0;
5108
5326
  var idleStatus = () => IDLE_WORKSPACE_OUTPUTS_STATUS;
5109
5327
  function useWorkspaceOutputs(provider, workspaceId, settings, enabled) {
5110
5328
  const providerV2 = provider && enabled ? getFileSystemProviderV25(provider) : null;
5111
- const [scheduler, setScheduler] = useState12(null);
5112
- useEffect13(() => {
5329
+ const [scheduler, setScheduler] = useState13(null);
5330
+ useEffect14(() => {
5113
5331
  if (!providerV2 || !workspaceId) {
5114
5332
  setScheduler(null);
5115
5333
  return;
@@ -5130,7 +5348,7 @@ function useWorkspaceOutputs(provider, workspaceId, settings, enabled) {
5130
5348
  next.dispose();
5131
5349
  };
5132
5350
  }, [providerV2, workspaceId]);
5133
- useEffect13(() => {
5351
+ useEffect14(() => {
5134
5352
  scheduler?.updateSettings(settings);
5135
5353
  }, [scheduler, settings]);
5136
5354
  const status = useSyncExternalStore2(
@@ -5165,22 +5383,22 @@ async function assertNotGeneratedCatalog(provider, path) {
5165
5383
  }
5166
5384
 
5167
5385
  // src/WorkspaceSettings/GeneratedFileView.tsx
5168
- import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
5386
+ import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
5169
5387
  function GeneratedFileNotice({ kind, onOpenSettings, onBack }) {
5170
- return /* @__PURE__ */ jsxs11("div", { className: "db-generated-file-notice", role: "note", children: [
5171
- onBack && /* @__PURE__ */ jsx12("button", { type: "button", className: "db-generated-file-back", onClick: onBack, children: "Back to files" }),
5172
- /* @__PURE__ */ jsxs11("span", { className: "db-generated-file-notice-text", children: [
5173
- /* @__PURE__ */ jsx12("strong", { children: "Generated by DocBlocks \xB7 read-only." }),
5388
+ return /* @__PURE__ */ jsxs12("div", { className: "db-generated-file-notice", role: "note", children: [
5389
+ onBack && /* @__PURE__ */ jsx13("button", { type: "button", className: "db-generated-file-back", onClick: onBack, children: "Back to files" }),
5390
+ /* @__PURE__ */ jsxs12("span", { className: "db-generated-file-notice-text", children: [
5391
+ /* @__PURE__ */ jsx13("strong", { children: "Generated by DocBlocks \xB7 read-only." }),
5174
5392
  " ",
5175
5393
  kind === "catalog-html" ? "This catalog page is rebuilt from the documents in this folder as you save." : "This catalog data is rebuilt from the documents in this folder as you save."
5176
5394
  ] }),
5177
- onOpenSettings && /* @__PURE__ */ jsx12("button", { type: "button", className: "db-git-secondary-btn", onClick: onOpenSettings, children: "Catalog settings\u2026" })
5395
+ onOpenSettings && /* @__PURE__ */ jsx13("button", { type: "button", className: "db-git-secondary-btn", onClick: onOpenSettings, children: "Catalog settings\u2026" })
5178
5396
  ] });
5179
5397
  }
5180
5398
  function GeneratedCatalogPage({ html, fileName, ...notice }) {
5181
- return /* @__PURE__ */ jsxs11("div", { className: "db-generated-file", children: [
5182
- /* @__PURE__ */ jsx12(GeneratedFileNotice, { kind: "catalog-html", ...notice }),
5183
- /* @__PURE__ */ jsx12(
5399
+ return /* @__PURE__ */ jsxs12("div", { className: "db-generated-file", children: [
5400
+ /* @__PURE__ */ jsx13(GeneratedFileNotice, { kind: "catalog-html", ...notice }),
5401
+ /* @__PURE__ */ jsx13(
5184
5402
  "iframe",
5185
5403
  {
5186
5404
  className: "db-generated-file-preview",
@@ -5193,10 +5411,10 @@ function GeneratedCatalogPage({ html, fileName, ...notice }) {
5193
5411
  ] });
5194
5412
  }
5195
5413
  function GeneratedFileFrame({ kind, children, ...notice }) {
5196
- if (!kind) return /* @__PURE__ */ jsx12(Fragment7, { children });
5197
- return /* @__PURE__ */ jsxs11("div", { className: "db-generated-file", children: [
5198
- /* @__PURE__ */ jsx12(GeneratedFileNotice, { kind, ...notice }),
5199
- /* @__PURE__ */ jsx12("div", { className: "db-generated-file-body", children })
5414
+ if (!kind) return /* @__PURE__ */ jsx13(Fragment8, { children });
5415
+ return /* @__PURE__ */ jsxs12("div", { className: "db-generated-file", children: [
5416
+ /* @__PURE__ */ jsx13(GeneratedFileNotice, { kind, ...notice }),
5417
+ /* @__PURE__ */ jsx13("div", { className: "db-generated-file-body", children })
5200
5418
  ] });
5201
5419
  }
5202
5420
 
@@ -5208,14 +5426,14 @@ import {
5208
5426
  } from "@bendyline/docblocks/workspace-settings";
5209
5427
 
5210
5428
  // src/hooks/useDocumentSession.ts
5211
- import { useState as useState13, useSyncExternalStore as useSyncExternalStore3 } from "react";
5429
+ import { useState as useState14, useSyncExternalStore as useSyncExternalStore3 } from "react";
5212
5430
  import {
5213
5431
  DocumentRecoveryJournal,
5214
5432
  DocumentSession,
5215
5433
  getDefaultDocumentRecoveryStorage
5216
5434
  } from "@bendyline/docblocks/document";
5217
5435
  function useDocumentSession(autoSaveDelayMs = 500) {
5218
- const [session] = useState13(
5436
+ const [session] = useState14(
5219
5437
  () => new DocumentSession({
5220
5438
  autoSaveDelayMs,
5221
5439
  recoveryJournal: new DocumentRecoveryJournal(getDefaultDocumentRecoveryStorage())
@@ -5231,14 +5449,14 @@ function useDocumentSession(autoSaveDelayMs = 500) {
5231
5449
 
5232
5450
  // src/Export/DeferredExportToolbarControls.tsx
5233
5451
  import { lazy, Suspense } from "react";
5234
- import { jsx as jsx13 } from "react/jsx-runtime";
5452
+ import { jsx as jsx14 } from "react/jsx-runtime";
5235
5453
  var ExportToolbarControlsImplementation = lazy(
5236
- () => import("./ExportToolbarControls-4LYTXGT3.js").then((module) => ({
5454
+ () => import("./ExportToolbarControls-ZOYH4I36.js").then((module) => ({
5237
5455
  default: module.ExportToolbarControls
5238
5456
  }))
5239
5457
  );
5240
5458
  function ExportToolbarControls(props) {
5241
- return /* @__PURE__ */ jsx13(Suspense, { fallback: null, children: /* @__PURE__ */ jsx13(ExportToolbarControlsImplementation, { ...props }) });
5459
+ return /* @__PURE__ */ jsx14(Suspense, { fallback: null, children: /* @__PURE__ */ jsx14(ExportToolbarControlsImplementation, { ...props }) });
5242
5460
  }
5243
5461
 
5244
5462
  // src/Export/host-export-save.ts
@@ -5278,17 +5496,17 @@ async function saveBlobToHost(exports, documentId, blob, filename, grantId) {
5278
5496
  }
5279
5497
 
5280
5498
  // src/Git/useGit.ts
5281
- import { useCallback as useCallback13, useEffect as useEffect15, useMemo as useMemo3, useRef as useRef13, useState as useState15 } from "react";
5499
+ import { useCallback as useCallback13, useEffect as useEffect16, useMemo as useMemo3, useRef as useRef13, useState as useState16 } from "react";
5282
5500
  import { maybeGetDocBlocksHost as maybeGetDocBlocksHost2 } from "@bendyline/docblocks/host";
5283
5501
 
5284
5502
  // src/Git/useGitStatus.ts
5285
- import { useCallback as useCallback12, useEffect as useEffect14, useRef as useRef12, useState as useState14 } from "react";
5503
+ import { useCallback as useCallback12, useEffect as useEffect15, useRef as useRef12, useState as useState15 } from "react";
5286
5504
  var SCHEDULE_REFRESH_MS = 1500;
5287
5505
  function statusKey(status) {
5288
5506
  return JSON.stringify(status);
5289
5507
  }
5290
5508
  function useGitStatus(gitApi, repositoryId, enabled) {
5291
- const [status, setStatus] = useState14(null);
5509
+ const [status, setStatus] = useState15(null);
5292
5510
  const lastKeyRef = useRef12(null);
5293
5511
  const timerRef = useRef12(null);
5294
5512
  const generationRef = useRef12(0);
@@ -5298,7 +5516,7 @@ function useGitStatus(gitApi, repositoryId, enabled) {
5298
5516
  lastKeyRef.current = key;
5299
5517
  setStatus(next);
5300
5518
  }, []);
5301
- useEffect14(() => {
5519
+ useEffect15(() => {
5302
5520
  generationRef.current += 1;
5303
5521
  if (timerRef.current) {
5304
5522
  clearTimeout(timerRef.current);
@@ -5337,7 +5555,7 @@ function useGitStatus(gitApi, repositoryId, enabled) {
5337
5555
  refresh();
5338
5556
  }, SCHEDULE_REFRESH_MS);
5339
5557
  }, [refresh]);
5340
- useEffect14(() => {
5558
+ useEffect15(() => {
5341
5559
  return () => {
5342
5560
  if (timerRef.current) clearTimeout(timerRef.current);
5343
5561
  };
@@ -5363,8 +5581,8 @@ function useGit(provider, requestedWorkspaceId, theme, onWorkingTreeChanged) {
5363
5581
  const host = maybeGetDocBlocksHost2();
5364
5582
  const gitApi = host?.git ?? null;
5365
5583
  const workspaceId = gitApi ? requestedWorkspaceId : null;
5366
- const [capabilities, setCapabilities] = useState15(null);
5367
- useEffect15(() => {
5584
+ const [capabilities, setCapabilities] = useState16(null);
5585
+ useEffect16(() => {
5368
5586
  if (!gitApi) return;
5369
5587
  let cancelled = false;
5370
5588
  let timer = null;
@@ -5390,9 +5608,9 @@ function useGit(provider, requestedWorkspaceId, theme, onWorkingTreeChanged) {
5390
5608
  };
5391
5609
  }, [gitApi]);
5392
5610
  const available = gitApi !== null && capabilities?.gitAvailable === true;
5393
- const [repo, setRepo] = useState15(null);
5394
- const [remoteWeb, setRemoteWeb] = useState15(null);
5395
- const [pendingGrant, setPendingGrant] = useState15(null);
5611
+ const [repo, setRepo] = useState16(null);
5612
+ const [remoteWeb, setRemoteWeb] = useState16(null);
5613
+ const [pendingGrant, setPendingGrant] = useState16(null);
5396
5614
  const loadRemote = useCallback13(
5397
5615
  (repositoryId2, isCancelled) => {
5398
5616
  if (!gitApi) return;
@@ -5407,7 +5625,7 @@ function useGit(provider, requestedWorkspaceId, theme, onWorkingTreeChanged) {
5407
5625
  },
5408
5626
  [gitApi]
5409
5627
  );
5410
- useEffect15(() => {
5628
+ useEffect16(() => {
5411
5629
  setRepo(null);
5412
5630
  setRemoteWeb(null);
5413
5631
  setPendingGrant(null);
@@ -5433,7 +5651,7 @@ function useGit(provider, requestedWorkspaceId, theme, onWorkingTreeChanged) {
5433
5651
  cancelled = true;
5434
5652
  };
5435
5653
  }, [gitApi, workspaceId, available, loadRemote]);
5436
- const [grantBusy, setGrantBusy] = useState15(false);
5654
+ const [grantBusy, setGrantBusy] = useState16(false);
5437
5655
  const enableExpandedRepo = useCallback13(
5438
5656
  async (opts) => {
5439
5657
  if (!gitApi || !workspaceId) return false;
@@ -5455,9 +5673,9 @@ function useGit(provider, requestedWorkspaceId, theme, onWorkingTreeChanged) {
5455
5673
  const isRepo = repositoryId !== null;
5456
5674
  const { status, refresh, scheduleRefresh } = useGitStatus(gitApi, repositoryId, isRepo);
5457
5675
  const badges = useMemo3(() => buildBadgeMap(status?.changes ?? []), [status]);
5458
- const [busy, setBusy] = useState15(null);
5459
- const [lastResult, setLastResult] = useState15(null);
5460
- const [dialog, setDialog] = useState15({ kind: "none" });
5676
+ const [busy, setBusy] = useState16(null);
5677
+ const [lastResult, setLastResult] = useState16(null);
5678
+ const [dialog, setDialog] = useState16({ kind: "none" });
5461
5679
  const openDialog = useCallback13((next) => {
5462
5680
  setLastResult(null);
5463
5681
  setDialog(next);
@@ -5478,11 +5696,11 @@ function useGit(provider, requestedWorkspaceId, theme, onWorkingTreeChanged) {
5478
5696
  []
5479
5697
  );
5480
5698
  const statusRef = useRef13(status);
5481
- useEffect15(() => {
5699
+ useEffect16(() => {
5482
5700
  statusRef.current = status;
5483
5701
  }, [status]);
5484
5702
  const workingTreeChangedRef = useRef13(onWorkingTreeChanged);
5485
- useEffect15(() => {
5703
+ useEffect16(() => {
5486
5704
  workingTreeChangedRef.current = onWorkingTreeChanged;
5487
5705
  }, [onWorkingTreeChanged]);
5488
5706
  const runAction = useCallback13(
@@ -5693,7 +5911,7 @@ function retainFileSystemProvider(provider) {
5693
5911
  }
5694
5912
 
5695
5913
  // src/DocBlocksShell/document-title.ts
5696
- import { useEffect as useEffect16 } from "react";
5914
+ import { useEffect as useEffect17 } from "react";
5697
5915
  var APP_TITLE = "DocBlocks";
5698
5916
  var INSTALLED_DISPLAY_QUERIES = [
5699
5917
  "(display-mode: window-controls-overlay)",
@@ -5717,7 +5935,7 @@ function titleForSelectedFile(selectedFile, homeDocumentTitle = APP_TITLE, homeD
5717
5935
  return includeAppName ? `${name} - ${APP_TITLE}` : name;
5718
5936
  }
5719
5937
  function useDocumentTitle(selectedFile, homeDocumentTitle, homeDocumentPath) {
5720
- useEffect16(() => {
5938
+ useEffect17(() => {
5721
5939
  if (typeof document === "undefined") return;
5722
5940
  const displayQueries = typeof globalThis.matchMedia === "function" ? INSTALLED_DISPLAY_QUERIES.map((query) => globalThis.matchMedia(query)) : [];
5723
5941
  const updateTitle = () => {
@@ -6041,13 +6259,13 @@ function summariseImport(result) {
6041
6259
  }
6042
6260
 
6043
6261
  // src/components/usePromptDialog.ts
6044
- import React2, { useCallback as useCallback15, useEffect as useEffect18, useRef as useRef15, useState as useState17 } from "react";
6262
+ import React2, { useCallback as useCallback15, useEffect as useEffect19, useRef as useRef15, useState as useState18 } from "react";
6045
6263
 
6046
6264
  // src/components/PromptDialog.tsx
6047
- import { useCallback as useCallback14, useEffect as useEffect17, useId as useId3, useRef as useRef14, useState as useState16 } from "react";
6048
- import { Fragment as Fragment8, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
6265
+ import { useCallback as useCallback14, useEffect as useEffect18, useId as useId3, useRef as useRef14, useState as useState17 } from "react";
6266
+ import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
6049
6267
  function PromptDialog({ request, onSettle }) {
6050
- const [value, setValue] = useState16(request.initialValue ?? "");
6268
+ const [value, setValue] = useState17(request.initialValue ?? "");
6051
6269
  const inputRef = useRef14(null);
6052
6270
  const inputId = useId3();
6053
6271
  const cancel = useCallback14(() => onSettle(null), [onSettle]);
@@ -6056,22 +6274,22 @@ function PromptDialog({ request, onSettle }) {
6056
6274
  onSettle(value);
6057
6275
  }, [onSettle, value]);
6058
6276
  const initialSelection = request.initialSelection;
6059
- useEffect17(() => {
6277
+ useEffect18(() => {
6060
6278
  const input = inputRef.current;
6061
6279
  if (!input) return;
6062
6280
  if (initialSelection) input.setSelectionRange(initialSelection[0], initialSelection[1]);
6063
6281
  else input.select();
6064
6282
  }, []);
6065
- return /* @__PURE__ */ jsx14(
6283
+ return /* @__PURE__ */ jsx15(
6066
6284
  Dialog,
6067
6285
  {
6068
6286
  title: request.title,
6069
6287
  onClose: cancel,
6070
6288
  initialFocusRef: inputRef,
6071
6289
  closeOnBackdrop: false,
6072
- footer: /* @__PURE__ */ jsxs12(Fragment8, { children: [
6073
- /* @__PURE__ */ jsx14("button", { type: "button", className: "db-git-secondary-btn", onClick: cancel, children: "Cancel" }),
6074
- /* @__PURE__ */ jsx14(
6290
+ footer: /* @__PURE__ */ jsxs13(Fragment9, { children: [
6291
+ /* @__PURE__ */ jsx15("button", { type: "button", className: "db-git-secondary-btn", onClick: cancel, children: "Cancel" }),
6292
+ /* @__PURE__ */ jsx15(
6075
6293
  "button",
6076
6294
  {
6077
6295
  type: "button",
@@ -6082,9 +6300,9 @@ function PromptDialog({ request, onSettle }) {
6082
6300
  }
6083
6301
  )
6084
6302
  ] }),
6085
- children: /* @__PURE__ */ jsxs12("div", { className: "db-git-form-row", children: [
6086
- /* @__PURE__ */ jsx14("label", { className: "db-git-form-label", htmlFor: inputId, children: request.label }),
6087
- /* @__PURE__ */ jsx14(
6303
+ children: /* @__PURE__ */ jsxs13("div", { className: "db-git-form-row", children: [
6304
+ /* @__PURE__ */ jsx15("label", { className: "db-git-form-label", htmlFor: inputId, children: request.label }),
6305
+ /* @__PURE__ */ jsx15(
6088
6306
  "input",
6089
6307
  {
6090
6308
  id: inputId,
@@ -6107,7 +6325,7 @@ function PromptDialog({ request, onSettle }) {
6107
6325
 
6108
6326
  // src/components/usePromptDialog.ts
6109
6327
  function usePromptDialog() {
6110
- const [pending, setPending] = useState17(null);
6328
+ const [pending, setPending] = useState18(null);
6111
6329
  const pendingRef = useRef15(null);
6112
6330
  const nextIdRef = useRef15(0);
6113
6331
  const settlePending = useCallback15((value) => {
@@ -6126,7 +6344,7 @@ function usePromptDialog() {
6126
6344
  }),
6127
6345
  [settlePending]
6128
6346
  );
6129
- useEffect18(() => {
6347
+ useEffect19(() => {
6130
6348
  return () => settlePending(null);
6131
6349
  }, [settlePending]);
6132
6350
  const promptDialog = pending ? React2.createElement(PromptDialog, {
@@ -6139,14 +6357,14 @@ function usePromptDialog() {
6139
6357
  }
6140
6358
 
6141
6359
  // src/components/NewDocumentDialog.tsx
6142
- import { useCallback as useCallback16, useEffect as useEffect19, useId as useId4, useRef as useRef16, useState as useState18 } from "react";
6143
- import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
6360
+ import { useCallback as useCallback16, useEffect as useEffect20, useId as useId4, useRef as useRef16, useState as useState19 } from "react";
6361
+ import { Fragment as Fragment10, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
6144
6362
  function NewDocumentDialog({
6145
6363
  onSettle,
6146
6364
  initialFormat = "markdown"
6147
6365
  }) {
6148
- const [name, setName] = useState18("Untitled");
6149
- const [format, setFormat] = useState18(initialFormat);
6366
+ const [name, setName] = useState19("Untitled");
6367
+ const [format, setFormat] = useState19(initialFormat);
6150
6368
  const inputRef = useRef16(null);
6151
6369
  const nameId = useId4();
6152
6370
  const formatId = useId4();
@@ -6157,19 +6375,19 @@ function NewDocumentDialog({
6157
6375
  const submit = useCallback16(() => {
6158
6376
  if (filename) onSettle({ filename, format });
6159
6377
  }, [filename, format, onSettle]);
6160
- useEffect19(() => {
6378
+ useEffect20(() => {
6161
6379
  inputRef.current?.select();
6162
6380
  }, []);
6163
- return /* @__PURE__ */ jsx15(
6381
+ return /* @__PURE__ */ jsx16(
6164
6382
  Dialog,
6165
6383
  {
6166
6384
  title: "New document",
6167
6385
  onClose: cancel,
6168
6386
  initialFocusRef: inputRef,
6169
6387
  closeOnBackdrop: false,
6170
- footer: /* @__PURE__ */ jsxs13(Fragment9, { children: [
6171
- /* @__PURE__ */ jsx15("button", { type: "button", className: "db-git-secondary-btn", onClick: cancel, children: "Cancel" }),
6172
- /* @__PURE__ */ jsx15(
6388
+ footer: /* @__PURE__ */ jsxs14(Fragment10, { children: [
6389
+ /* @__PURE__ */ jsx16("button", { type: "button", className: "db-git-secondary-btn", onClick: cancel, children: "Cancel" }),
6390
+ /* @__PURE__ */ jsx16(
6173
6391
  "button",
6174
6392
  {
6175
6393
  type: "button",
@@ -6180,9 +6398,9 @@ function NewDocumentDialog({
6180
6398
  }
6181
6399
  )
6182
6400
  ] }),
6183
- children: /* @__PURE__ */ jsxs13("div", { className: "db-new-document-fields", children: [
6184
- /* @__PURE__ */ jsx15("label", { className: "db-git-form-label", htmlFor: nameId, children: "Document name" }),
6185
- /* @__PURE__ */ jsx15(
6401
+ children: /* @__PURE__ */ jsxs14("div", { className: "db-new-document-fields", children: [
6402
+ /* @__PURE__ */ jsx16("label", { className: "db-git-form-label", htmlFor: nameId, children: "Document name" }),
6403
+ /* @__PURE__ */ jsx16(
6186
6404
  "input",
6187
6405
  {
6188
6406
  id: nameId,
@@ -6198,8 +6416,8 @@ function NewDocumentDialog({
6198
6416
  }
6199
6417
  }
6200
6418
  ),
6201
- /* @__PURE__ */ jsx15("label", { className: "db-git-form-label", htmlFor: formatId, children: "Type" }),
6202
- /* @__PURE__ */ jsx15(
6419
+ /* @__PURE__ */ jsx16("label", { className: "db-git-form-label", htmlFor: formatId, children: "Type" }),
6420
+ /* @__PURE__ */ jsx16(
6203
6421
  "select",
6204
6422
  {
6205
6423
  id: formatId,
@@ -6207,10 +6425,10 @@ function NewDocumentDialog({
6207
6425
  "aria-describedby": hint ? hintId : void 0,
6208
6426
  value: format,
6209
6427
  onChange: (e) => setFormat(e.target.value),
6210
- children: /* @__PURE__ */ jsx15(NewFileFormatOptions, {})
6428
+ children: /* @__PURE__ */ jsx16(NewFileFormatOptions, {})
6211
6429
  }
6212
6430
  ),
6213
- hint && /* @__PURE__ */ jsx15("p", { id: hintId, className: "db-new-document-hint", children: hint })
6431
+ hint && /* @__PURE__ */ jsx16("p", { id: hintId, className: "db-new-document-hint", children: hint })
6214
6432
  ] })
6215
6433
  }
6216
6434
  );
@@ -6218,7 +6436,7 @@ function NewDocumentDialog({
6218
6436
 
6219
6437
  // src/DocBlocksShell/EditorErrorBoundary.tsx
6220
6438
  import { Component } from "react";
6221
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
6439
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
6222
6440
  var EditorErrorBoundary = class extends Component {
6223
6441
  constructor() {
6224
6442
  super(...arguments);
@@ -6233,11 +6451,11 @@ var EditorErrorBoundary = class extends Component {
6233
6451
  render() {
6234
6452
  const { error } = this.state;
6235
6453
  if (!error) return this.props.children;
6236
- return /* @__PURE__ */ jsx16("div", { className: "db-shell-empty db-shell-empty--workspace", role: "alert", children: /* @__PURE__ */ jsxs14("div", { className: "db-workspace-empty-content", children: [
6237
- /* @__PURE__ */ jsx16("h1", { children: "This document couldn\u2019t be displayed" }),
6238
- /* @__PURE__ */ jsx16("p", { children: "The editor ran into a problem drawing it. The document itself is unaffected." }),
6239
- /* @__PURE__ */ jsx16("div", { className: "db-workspace-empty-actions", children: /* @__PURE__ */ jsx16("button", { type: "button", onClick: () => this.setState({ error: null }), children: "Try again" }) }),
6240
- /* @__PURE__ */ jsx16("p", { className: "db-workspace-empty-hint", children: error.message })
6454
+ return /* @__PURE__ */ jsx17("div", { className: "db-shell-empty db-shell-empty--workspace", role: "alert", children: /* @__PURE__ */ jsxs15("div", { className: "db-workspace-empty-content", children: [
6455
+ /* @__PURE__ */ jsx17("h1", { children: "This document couldn\u2019t be displayed" }),
6456
+ /* @__PURE__ */ jsx17("p", { children: "The editor ran into a problem drawing it. The document itself is unaffected." }),
6457
+ /* @__PURE__ */ jsx17("div", { className: "db-workspace-empty-actions", children: /* @__PURE__ */ jsx17("button", { type: "button", onClick: () => this.setState({ error: null }), children: "Try again" }) }),
6458
+ /* @__PURE__ */ jsx17("p", { className: "db-workspace-empty-hint", children: error.message })
6241
6459
  ] }) });
6242
6460
  }
6243
6461
  };
@@ -6354,81 +6572,6 @@ function loadLastState(storage = localStorage) {
6354
6572
  }
6355
6573
  }
6356
6574
 
6357
- // src/layout/form-factor.ts
6358
- var DB_BREAKPOINTS = Object.freeze({
6359
- /** Inclusive upper bound for phones and narrow slivers. */
6360
- compactMax: 720,
6361
- /** Inclusive upper bound for tablet-portrait and half-screen laptops. */
6362
- mediumMax: 1023,
6363
- /** Inclusive upper bound for tablet-landscape and laptops. */
6364
- expandedMax: 1439,
6365
- /**
6366
- * Largest short edge still considered a phone. Orientation-independent on
6367
- * purpose: a phone turned sideways is 844x390, which is `medium` by width but
6368
- * is obviously not a tablet. The widest phone short edge in circulation is
6369
- * around 430px; the narrowest tablet short edge is the iPad mini's 744px, so
6370
- * 520 sits in open space between them.
6371
- */
6372
- phoneMaxShortEdge: 520
6373
- });
6374
- var SIDEBAR_WIDTH_DEFAULT = 320;
6375
- var SIDEBAR_WIDTH_MIN = 320;
6376
- var SIDEBAR_WIDTH_MAX = 600;
6377
- var SIDEBAR_COLLAPSE_THRESHOLD = SIDEBAR_WIDTH_MIN;
6378
- var DB_LAYOUT_MINIMA = Object.freeze({
6379
- /**
6380
- * Narrower than this, an editor pane beside the sidebar is not worth the
6381
- * split. Paired with `SIDEBAR_WIDTH_MIN` to derive `splitPaneAllowed`.
6382
- */
6383
- editorMinWidth: 480
6384
- });
6385
- var SPLIT_PANE_MIN_WIDTH = SIDEBAR_WIDTH_MIN + DB_LAYOUT_MINIMA.editorMinWidth;
6386
- function classifyWidth(width) {
6387
- if (width <= DB_BREAKPOINTS.compactMax) return "compact";
6388
- if (width <= DB_BREAKPOINTS.mediumMax) return "medium";
6389
- if (width <= DB_BREAKPOINTS.expandedMax) return "expanded";
6390
- return "wide";
6391
- }
6392
- function classifyFormFactor(input) {
6393
- const widthClass = classifyWidth(input.width);
6394
- const orientation = input.height >= input.width ? "portrait" : "landscape";
6395
- let formFactor;
6396
- if (input.pointer === "fine") {
6397
- formFactor = "desktop";
6398
- } else if (Math.min(input.width, input.height) <= DB_BREAKPOINTS.phoneMaxShortEdge) {
6399
- formFactor = "phone";
6400
- } else {
6401
- formFactor = orientation === "portrait" ? "tablet-portrait" : "tablet-landscape";
6402
- }
6403
- return {
6404
- ...input,
6405
- widthClass,
6406
- orientation,
6407
- formFactor,
6408
- splitPaneAllowed: input.width >= SPLIT_PANE_MIN_WIDTH
6409
- };
6410
- }
6411
- function resolveLayoutMode(formFactor, preference) {
6412
- if (!formFactor.splitPaneAllowed) return "single-pane";
6413
- if (preference === "collapsed") return "single-pane";
6414
- if (preference === "pinned") return "split-pane";
6415
- if (formFactor.widthClass === "expanded" || formFactor.widthClass === "wide") {
6416
- return "split-pane";
6417
- }
6418
- if (formFactor.pointer === "fine") return "split-pane";
6419
- return "single-pane";
6420
- }
6421
- function formFactorDataAttributes(formFactor, layoutMode) {
6422
- return Object.freeze({
6423
- "data-db-width": formFactor.widthClass,
6424
- "data-db-form-factor": formFactor.formFactor,
6425
- "data-db-pointer": formFactor.pointer,
6426
- "data-db-hover": formFactor.hover,
6427
- "data-db-orientation": formFactor.orientation,
6428
- "data-db-layout": layoutMode
6429
- });
6430
- }
6431
-
6432
6575
  // src/DocBlocksShell/shell-preferences.ts
6433
6576
  var WELCOME_GATEWAY_KEY = "docblocks:welcomeGatewayDismissed";
6434
6577
  var SIDEBAR_WIDTH_KEY = "docblocks:sidebarWidth";
@@ -6527,34 +6670,6 @@ function saveViewPreferences(preferences) {
6527
6670
 
6528
6671
  // src/layout/useFormFactor.ts
6529
6672
  import { useEffect as useEffect21, useMemo as useMemo4, useState as useState20 } from "react";
6530
-
6531
- // src/layout/useMediaQuery.ts
6532
- import { useEffect as useEffect20, useState as useState19 } from "react";
6533
- var INSTALLED_DISPLAY_QUERIES2 = [
6534
- "(display-mode: window-controls-overlay)",
6535
- "(display-mode: standalone)"
6536
- ];
6537
- function matchesMediaQuery(query) {
6538
- if (typeof globalThis.matchMedia !== "function") return false;
6539
- return globalThis.matchMedia(query).matches;
6540
- }
6541
- function isInstalledDisplayMode() {
6542
- return INSTALLED_DISPLAY_QUERIES2.some(matchesMediaQuery);
6543
- }
6544
- function useMediaQuery(query) {
6545
- const [matches, setMatches] = useState19(() => matchesMediaQuery(query));
6546
- useEffect20(() => {
6547
- if (typeof globalThis.matchMedia !== "function") return;
6548
- const list = globalThis.matchMedia(query);
6549
- const update = () => setMatches(list.matches);
6550
- update();
6551
- list.addEventListener("change", update);
6552
- return () => list.removeEventListener("change", update);
6553
- }, [query]);
6554
- return matches;
6555
- }
6556
-
6557
- // src/layout/useFormFactor.ts
6558
6673
  var COARSE_POINTER_QUERY = "(pointer: coarse)";
6559
6674
  var ANY_HOVER_QUERY = "(any-hover: hover)";
6560
6675
  function initialSize() {
@@ -6811,10 +6926,14 @@ function useEdgeSwipe({
6811
6926
  }
6812
6927
 
6813
6928
  // src/DocBlocksShell/useEditorFileDrop.ts
6814
- import { useEffect as useEffect27, useState as useState21 } from "react";
6929
+ import { useEffect as useEffect27, useRef as useRef18, useState as useState21 } from "react";
6815
6930
  var INTERNAL_DRAG_TYPE2 = "application/x-docblocks-entry";
6816
6931
  function useEditorFileDrop(targetRef, enabled, onFiles) {
6817
6932
  const [dropActive, setDropActive] = useState21(false);
6933
+ const onFilesRef = useRef18(onFiles);
6934
+ useEffect27(() => {
6935
+ onFilesRef.current = onFiles;
6936
+ }, [onFiles]);
6818
6937
  useEffect27(() => {
6819
6938
  const element = targetRef.current;
6820
6939
  if (!enabled || !element) {
@@ -6829,7 +6948,7 @@ function useEditorFileDrop(targetRef, enabled, onFiles) {
6829
6948
  if (items.length === 0) return false;
6830
6949
  return items.some((item) => {
6831
6950
  const file = item.getAsFile();
6832
- return file ? isEditorDocumentImportFile(file) : !item.type.toLowerCase().startsWith("image/");
6951
+ return file ? isEditorDocumentImportFile(file) : !isEditorMediaMimeType(item.type);
6833
6952
  });
6834
6953
  };
6835
6954
  const onDragEnter = (event) => {
@@ -6859,7 +6978,7 @@ function useEditorFileDrop(targetRef, enabled, onFiles) {
6859
6978
  if (files.length === 0) return;
6860
6979
  event.preventDefault();
6861
6980
  event.stopPropagation();
6862
- onFiles(files);
6981
+ onFilesRef.current(files);
6863
6982
  };
6864
6983
  element.addEventListener("dragenter", onDragEnter, true);
6865
6984
  element.addEventListener("dragover", onDragOver, true);
@@ -6872,14 +6991,14 @@ function useEditorFileDrop(targetRef, enabled, onFiles) {
6872
6991
  element.removeEventListener("drop", onDrop, true);
6873
6992
  setDropActive(false);
6874
6993
  };
6875
- }, [targetRef, enabled, onFiles]);
6994
+ }, [targetRef, enabled]);
6876
6995
  return dropActive;
6877
6996
  }
6878
6997
 
6879
6998
  // src/DocBlocksShell/useShellShortcuts.ts
6880
- import { useEffect as useEffect28, useRef as useRef18 } from "react";
6999
+ import { useEffect as useEffect28, useRef as useRef19 } from "react";
6881
7000
  function useShellShortcuts(handlers, layoutMode) {
6882
- const handlersRef = useRef18(handlers);
7001
+ const handlersRef = useRef19(handlers);
6883
7002
  handlersRef.current = handlers;
6884
7003
  useEffect28(() => {
6885
7004
  if (typeof window === "undefined") return;
@@ -6897,9 +7016,101 @@ function useShellShortcuts(handlers, layoutMode) {
6897
7016
  }, [layoutMode]);
6898
7017
  }
6899
7018
 
7019
+ // src/DocBlocksShell/DocumentConflictBanner.tsx
7020
+ import { useEffect as useEffect29, useState as useState22 } from "react";
7021
+
7022
+ // src/DocBlocksShell/conflict-summary.ts
7023
+ var SECOND_MS = 1e3;
7024
+ var MINUTE_MS2 = 60 * SECOND_MS;
7025
+ var HOUR_MS2 = 60 * MINUTE_MS2;
7026
+ var DAY_MS2 = 24 * HOUR_MS2;
7027
+ var shortDateFormatter2 = new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric" });
7028
+ function plural2(value, unit) {
7029
+ return `${value.toLocaleString()} ${unit}${value === 1 ? "" : "s"}`;
7030
+ }
7031
+ function describeAge(timestamp, now) {
7032
+ const elapsed = now - timestamp;
7033
+ if (elapsed < -MINUTE_MS2) return null;
7034
+ if (elapsed < 10 * SECOND_MS) return "just now";
7035
+ if (elapsed < MINUTE_MS2) return `${Math.floor(elapsed / (10 * SECOND_MS)) * 10} seconds ago`;
7036
+ if (elapsed < HOUR_MS2) return `${plural2(Math.floor(elapsed / MINUTE_MS2), "minute")} ago`;
7037
+ if (elapsed < DAY_MS2) return `${plural2(Math.floor(elapsed / HOUR_MS2), "hour")} ago`;
7038
+ if (elapsed < 2 * DAY_MS2) return "yesterday";
7039
+ if (elapsed < 7 * DAY_MS2) return `${plural2(Math.floor(elapsed / DAY_MS2), "day")} ago`;
7040
+ return `on ${shortDateFormatter2.format(new Date(timestamp))}`;
7041
+ }
7042
+ function describeVersion(label, content, verb, at, now) {
7043
+ const age = at === void 0 ? null : describeAge(at, now);
7044
+ const size = plural2(Array.from(content).length, "character");
7045
+ return `${label}: ${size}${age ? `, ${verb} ${age}` : ""}.`;
7046
+ }
7047
+ function localVersionTime(conflict) {
7048
+ return conflict.localEditedAt ?? conflict.recoveredDraftCapturedAt;
7049
+ }
7050
+ function describeConflictVersions(conflict, savedAt, now) {
7051
+ const local = describeVersion(
7052
+ conflict.recoveredDraft ? "Recovery draft" : "Your version",
7053
+ conflict.localContent,
7054
+ "edited",
7055
+ localVersionTime(conflict),
7056
+ now
7057
+ );
7058
+ const saved = conflict.externalContent === null ? "The saved file was deleted." : describeVersion("Saved file", conflict.externalContent, "updated", savedAt, now);
7059
+ return `${local} ${saved}`;
7060
+ }
7061
+
7062
+ // src/DocBlocksShell/DocumentConflictBanner.tsx
7063
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
7064
+ function DocumentConflictBanner({
7065
+ conflict,
7066
+ readSavedFile,
7067
+ onCompare,
7068
+ onDismiss
7069
+ }) {
7070
+ const [savedAt, setSavedAt] = useState22(void 0);
7071
+ const [now, setNow] = useState22(() => Date.now());
7072
+ useEffect29(() => {
7073
+ let disposed = false;
7074
+ setSavedAt(void 0);
7075
+ if (conflict.externalContent === null) return;
7076
+ void readSavedFile().then(
7077
+ (file) => {
7078
+ if (disposed || !file?.lastModified || file.content !== conflict.externalContent) return;
7079
+ const parsed = Date.parse(file.lastModified);
7080
+ if (Number.isFinite(parsed)) setSavedAt(parsed);
7081
+ },
7082
+ () => {
7083
+ }
7084
+ );
7085
+ return () => {
7086
+ disposed = true;
7087
+ };
7088
+ }, [readSavedFile, conflict.targetKey, conflict.externalContent, conflict.externalVersion]);
7089
+ const localAt = localVersionTime(conflict);
7090
+ useEffect29(() => {
7091
+ if (localAt === void 0 && savedAt === void 0) return;
7092
+ const newest = Math.max(localAt ?? 0, savedAt ?? 0);
7093
+ const timer = setTimeout(
7094
+ () => setNow(Date.now()),
7095
+ Date.now() - newest < MINUTE_MS2 ? 5e3 : 3e4
7096
+ );
7097
+ return () => clearTimeout(timer);
7098
+ }, [now, localAt, savedAt]);
7099
+ return /* @__PURE__ */ jsxs16("div", { className: "db-document-conflict", children: [
7100
+ /* @__PURE__ */ jsxs16("div", { className: "db-document-conflict-text", children: [
7101
+ /* @__PURE__ */ jsx18("span", { role: "alert", children: conflict.recoveredDraft ? "A recovery draft from a previous session differs from the saved file. The saved file may be newer. Choose which version to use." : "This document changed outside DocBlocks. Your unsaved version is still intact." }),
7102
+ /* @__PURE__ */ jsx18("span", { className: "db-document-conflict-details", children: describeConflictVersions(conflict, savedAt, now) })
7103
+ ] }),
7104
+ /* @__PURE__ */ jsxs16("div", { className: "db-document-conflict-actions", children: [
7105
+ /* @__PURE__ */ jsx18("button", { type: "button", onClick: onCompare, children: "Compare versions" }),
7106
+ /* @__PURE__ */ jsx18("button", { type: "button", onClick: onDismiss, children: "Dismiss" })
7107
+ ] })
7108
+ ] });
7109
+ }
7110
+
6900
7111
  // src/DocBlocksShell/UpdateAvailableNotice.tsx
6901
- import { useState as useState22 } from "react";
6902
- import { Fragment as Fragment10, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
7112
+ import { useState as useState23 } from "react";
7113
+ import { Fragment as Fragment11, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
6903
7114
  var UPDATE_PROMPT_ID = "db-update-available-prompt";
6904
7115
  function UpdateAvailableNotice({
6905
7116
  available,
@@ -6907,12 +7118,12 @@ function UpdateAvailableNotice({
6907
7118
  blocked = false,
6908
7119
  statusBarVisible
6909
7120
  }) {
6910
- const [promptOpen, setPromptOpen] = useState22(false);
6911
- const [applying, setApplying] = useState22(false);
7121
+ const [promptOpen, setPromptOpen] = useState23(false);
7122
+ const [applying, setApplying] = useState23(false);
6912
7123
  if (!available || !onApplyUpdate) return null;
6913
7124
  const promptVisible = promptOpen && !blocked;
6914
- return /* @__PURE__ */ jsxs15(Fragment10, { children: [
6915
- /* @__PURE__ */ jsx17(
7125
+ return /* @__PURE__ */ jsxs17(Fragment11, { children: [
7126
+ /* @__PURE__ */ jsx19(
6916
7127
  "button",
6917
7128
  {
6918
7129
  type: "button",
@@ -6926,16 +7137,16 @@ function UpdateAvailableNotice({
6926
7137
  children: "Update available"
6927
7138
  }
6928
7139
  ),
6929
- promptVisible && /* @__PURE__ */ jsxs15(
7140
+ promptVisible && /* @__PURE__ */ jsxs17(
6930
7141
  "div",
6931
7142
  {
6932
7143
  id: UPDATE_PROMPT_ID,
6933
7144
  className: `db-update-banner${statusBarVisible ? "" : " db-update-banner--floating"}`,
6934
7145
  role: "alert",
6935
7146
  children: [
6936
- /* @__PURE__ */ jsx17("span", { children: "A new version of DocBlocks is available. Reload to update the editor and site pages." }),
6937
- /* @__PURE__ */ jsxs15("div", { className: "db-update-banner-actions", children: [
6938
- /* @__PURE__ */ jsx17(
7147
+ /* @__PURE__ */ jsx19("span", { children: "A new version of DocBlocks is available. Reload to update the editor and site pages." }),
7148
+ /* @__PURE__ */ jsxs17("div", { className: "db-update-banner-actions", children: [
7149
+ /* @__PURE__ */ jsx19(
6939
7150
  "button",
6940
7151
  {
6941
7152
  type: "button",
@@ -6947,7 +7158,7 @@ function UpdateAvailableNotice({
6947
7158
  children: applying ? "Updating\u2026" : "Reload"
6948
7159
  }
6949
7160
  ),
6950
- /* @__PURE__ */ jsx17("button", { type: "button", onClick: () => setPromptOpen(false), disabled: applying, children: "Later" })
7161
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: () => setPromptOpen(false), disabled: applying, children: "Later" })
6951
7162
  ] })
6952
7163
  ]
6953
7164
  }
@@ -6956,7 +7167,7 @@ function UpdateAvailableNotice({
6956
7167
  }
6957
7168
 
6958
7169
  // src/DocBlocksShell/WelcomeScreen.tsx
6959
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
7170
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
6960
7171
  var WELCOME_HEADLINE = "The Markdown editor that turns one file into anything.";
6961
7172
  var WELCOME_SUMMARY = "Write the way you normally would, then share the same file as a PDF, a Word document, a slide deck, or a video.";
6962
7173
  var WELCOME_PRIVACY_NOTE = "No account, and your documents stay on this device.";
@@ -6967,8 +7178,8 @@ function WelcomeScreen({
6967
7178
  onDismiss,
6968
7179
  offerApps = false
6969
7180
  }) {
6970
- return /* @__PURE__ */ jsxs16("section", { className: "db-welcome-gateway", "aria-labelledby": "db-welcome-gateway-title", children: [
6971
- /* @__PURE__ */ jsx18(
7181
+ return /* @__PURE__ */ jsxs18("section", { className: "db-welcome-gateway", "aria-labelledby": "db-welcome-gateway-title", children: [
7182
+ /* @__PURE__ */ jsx20(
6972
7183
  "button",
6973
7184
  {
6974
7185
  type: "button",
@@ -6979,16 +7190,16 @@ function WelcomeScreen({
6979
7190
  children: "\xD7"
6980
7191
  }
6981
7192
  ),
6982
- /* @__PURE__ */ jsxs16("div", { className: "db-welcome-gateway-body", children: [
6983
- /* @__PURE__ */ jsxs16("div", { className: "db-welcome-gateway-copy", children: [
6984
- /* @__PURE__ */ jsx18("p", { className: "db-welcome-gateway-eyebrow", children: "Welcome to DocBlocks" }),
6985
- /* @__PURE__ */ jsx18("h1", { id: "db-welcome-gateway-title", children: WELCOME_HEADLINE }),
6986
- /* @__PURE__ */ jsx18("p", { children: WELCOME_SUMMARY }),
6987
- /* @__PURE__ */ jsx18("p", { className: "db-welcome-gateway-note", children: WELCOME_PRIVACY_NOTE }),
6988
- /* @__PURE__ */ jsxs16("div", { className: "db-welcome-gateway-actions", children: [
6989
- /* @__PURE__ */ jsx18("button", { type: "button", className: "db-welcome-gateway-primary", onClick: onCreateDocument, children: "Create a document" }),
6990
- /* @__PURE__ */ jsx18("button", { type: "button", className: "db-welcome-gateway-cta", onClick: onTour, children: "Tour the welcome document" }),
6991
- offerApps && /* @__PURE__ */ jsx18(
7193
+ /* @__PURE__ */ jsxs18("div", { className: "db-welcome-gateway-body", children: [
7194
+ /* @__PURE__ */ jsxs18("div", { className: "db-welcome-gateway-copy", children: [
7195
+ /* @__PURE__ */ jsx20("p", { className: "db-welcome-gateway-eyebrow", children: "Welcome to DocBlocks" }),
7196
+ /* @__PURE__ */ jsx20("h1", { id: "db-welcome-gateway-title", children: WELCOME_HEADLINE }),
7197
+ /* @__PURE__ */ jsx20("p", { children: WELCOME_SUMMARY }),
7198
+ /* @__PURE__ */ jsx20("p", { className: "db-welcome-gateway-note", children: WELCOME_PRIVACY_NOTE }),
7199
+ /* @__PURE__ */ jsxs18("div", { className: "db-welcome-gateway-actions", children: [
7200
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "db-welcome-gateway-primary", onClick: onCreateDocument, children: "Create a document" }),
7201
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "db-welcome-gateway-cta", onClick: onTour, children: "Tour the welcome document" }),
7202
+ offerApps && /* @__PURE__ */ jsx20(
6992
7203
  "a",
6993
7204
  {
6994
7205
  className: "db-welcome-gateway-apps",
@@ -7000,55 +7211,55 @@ function WelcomeScreen({
7000
7211
  )
7001
7212
  ] })
7002
7213
  ] }),
7003
- /* @__PURE__ */ jsx18(WelcomeLoop, {})
7214
+ /* @__PURE__ */ jsx20(WelcomeLoop, {})
7004
7215
  ] })
7005
7216
  ] });
7006
7217
  }
7007
7218
  function WelcomeLoop() {
7008
- return /* @__PURE__ */ jsxs16("div", { className: "db-welcome-loop", "aria-hidden": "true", children: [
7009
- /* @__PURE__ */ jsxs16("div", { className: "db-welcome-loop-source", children: [
7010
- /* @__PURE__ */ jsx18("span", { className: "db-welcome-loop-file", children: "Lisbon.md" }),
7011
- /* @__PURE__ */ jsxs16("code", { children: [
7012
- /* @__PURE__ */ jsx18("span", { className: "db-welcome-loop-mark", children: "# " }),
7219
+ return /* @__PURE__ */ jsxs18("div", { className: "db-welcome-loop", "aria-hidden": "true", children: [
7220
+ /* @__PURE__ */ jsxs18("div", { className: "db-welcome-loop-source", children: [
7221
+ /* @__PURE__ */ jsx20("span", { className: "db-welcome-loop-file", children: "Lisbon.md" }),
7222
+ /* @__PURE__ */ jsxs18("code", { children: [
7223
+ /* @__PURE__ */ jsx20("span", { className: "db-welcome-loop-mark", children: "# " }),
7013
7224
  "Lisbon in three days",
7014
7225
  "\n",
7015
7226
  "Trams, tiles, and pastries.",
7016
7227
  "\n\n",
7017
- /* @__PURE__ */ jsx18("span", { className: "db-welcome-loop-mark", children: "## " }),
7228
+ /* @__PURE__ */ jsx20("span", { className: "db-welcome-loop-mark", children: "## " }),
7018
7229
  "Day one",
7019
7230
  "\n",
7020
- /* @__PURE__ */ jsx18("span", { className: "db-welcome-loop-mark", children: "- " }),
7231
+ /* @__PURE__ */ jsx20("span", { className: "db-welcome-loop-mark", children: "- " }),
7021
7232
  "Ride Tram 28",
7022
7233
  "\n",
7023
- /* @__PURE__ */ jsx18("span", { className: "db-welcome-loop-mark", children: "- " }),
7234
+ /* @__PURE__ */ jsx20("span", { className: "db-welcome-loop-mark", children: "- " }),
7024
7235
  "Sunset at Gra\xE7a"
7025
7236
  ] })
7026
7237
  ] }),
7027
- /* @__PURE__ */ jsx18("div", { className: "db-welcome-loop-arrow", children: "\u2192" }),
7028
- /* @__PURE__ */ jsxs16("div", { className: "db-welcome-loop-stage", children: [
7029
- /* @__PURE__ */ jsxs16("div", { className: "db-welcome-loop-frame db-welcome-loop-frame--page", children: [
7030
- /* @__PURE__ */ jsx18("strong", { children: "Lisbon in three days" }),
7031
- /* @__PURE__ */ jsx18("span", { children: "Trams, tiles, and pastries." }),
7032
- /* @__PURE__ */ jsx18("em", { children: "Day one" }),
7033
- /* @__PURE__ */ jsx18("span", { children: "\u2022 Ride Tram 28" }),
7034
- /* @__PURE__ */ jsx18("span", { children: "\u2022 Sunset at Gra\xE7a" })
7238
+ /* @__PURE__ */ jsx20("div", { className: "db-welcome-loop-arrow", children: "\u2192" }),
7239
+ /* @__PURE__ */ jsxs18("div", { className: "db-welcome-loop-stage", children: [
7240
+ /* @__PURE__ */ jsxs18("div", { className: "db-welcome-loop-frame db-welcome-loop-frame--page", children: [
7241
+ /* @__PURE__ */ jsx20("strong", { children: "Lisbon in three days" }),
7242
+ /* @__PURE__ */ jsx20("span", { children: "Trams, tiles, and pastries." }),
7243
+ /* @__PURE__ */ jsx20("em", { children: "Day one" }),
7244
+ /* @__PURE__ */ jsx20("span", { children: "\u2022 Ride Tram 28" }),
7245
+ /* @__PURE__ */ jsx20("span", { children: "\u2022 Sunset at Gra\xE7a" })
7035
7246
  ] }),
7036
- /* @__PURE__ */ jsxs16("div", { className: "db-welcome-loop-frame db-welcome-loop-frame--slide", children: [
7037
- /* @__PURE__ */ jsx18("strong", { children: "Lisbon in three days" }),
7038
- /* @__PURE__ */ jsx18("span", { children: "Trams, tiles, and pastries." })
7247
+ /* @__PURE__ */ jsxs18("div", { className: "db-welcome-loop-frame db-welcome-loop-frame--slide", children: [
7248
+ /* @__PURE__ */ jsx20("strong", { children: "Lisbon in three days" }),
7249
+ /* @__PURE__ */ jsx20("span", { children: "Trams, tiles, and pastries." })
7039
7250
  ] }),
7040
- /* @__PURE__ */ jsxs16("div", { className: "db-welcome-loop-frame db-welcome-loop-frame--video", children: [
7041
- /* @__PURE__ */ jsx18("em", { children: "Day one" }),
7042
- /* @__PURE__ */ jsx18("span", { children: "\u2022 Ride Tram 28" }),
7043
- /* @__PURE__ */ jsx18("span", { children: "\u2022 Sunset at Gra\xE7a" }),
7044
- /* @__PURE__ */ jsx18("i", { className: "db-welcome-loop-play", children: "\u25B6" }),
7045
- /* @__PURE__ */ jsx18("i", { className: "db-welcome-loop-progress" })
7251
+ /* @__PURE__ */ jsxs18("div", { className: "db-welcome-loop-frame db-welcome-loop-frame--video", children: [
7252
+ /* @__PURE__ */ jsx20("em", { children: "Day one" }),
7253
+ /* @__PURE__ */ jsx20("span", { children: "\u2022 Ride Tram 28" }),
7254
+ /* @__PURE__ */ jsx20("span", { children: "\u2022 Sunset at Gra\xE7a" }),
7255
+ /* @__PURE__ */ jsx20("i", { className: "db-welcome-loop-play", children: "\u25B6" }),
7256
+ /* @__PURE__ */ jsx20("i", { className: "db-welcome-loop-progress" })
7046
7257
  ] })
7047
7258
  ] }),
7048
- /* @__PURE__ */ jsxs16("ol", { className: "db-welcome-loop-labels", children: [
7049
- /* @__PURE__ */ jsx18("li", { children: "PDF" }),
7050
- /* @__PURE__ */ jsx18("li", { children: "Slides" }),
7051
- /* @__PURE__ */ jsx18("li", { children: "Video" })
7259
+ /* @__PURE__ */ jsxs18("ol", { className: "db-welcome-loop-labels", children: [
7260
+ /* @__PURE__ */ jsx20("li", { children: "PDF" }),
7261
+ /* @__PURE__ */ jsx20("li", { children: "Slides" }),
7262
+ /* @__PURE__ */ jsx20("li", { children: "Video" })
7052
7263
  ] })
7053
7264
  ] });
7054
7265
  }
@@ -7116,7 +7327,7 @@ function useDocumentLinkProvider(index, selectedFile, ensureIndex) {
7116
7327
  }
7117
7328
 
7118
7329
  // src/WorkspaceIndex/useWorkspaceIndex.ts
7119
- import { useCallback as useCallback18, useEffect as useEffect29, useMemo as useMemo5, useRef as useRef19, useState as useState23, useSyncExternalStore as useSyncExternalStore4 } from "react";
7330
+ import { useCallback as useCallback18, useEffect as useEffect30, useMemo as useMemo5, useRef as useRef20, useState as useState24, useSyncExternalStore as useSyncExternalStore4 } from "react";
7120
7331
  import { getFileSystemProviderV2 as getFileSystemProviderV29 } from "@bendyline/docblocks/filesystem";
7121
7332
  import { maybeGetDocBlocksHost as maybeGetDocBlocksHost3 } from "@bendyline/docblocks/host";
7122
7333
  var IDLE_WORKSPACE_INDEX_STATUS = Object.freeze({
@@ -7148,9 +7359,9 @@ function whenIdle(callback) {
7148
7359
  }
7149
7360
  function useWorkspaceIndex(provider, workspaceId, mode = "eager") {
7150
7361
  const providerV2 = provider && mode !== "off" ? getFileSystemProviderV29(provider) : null;
7151
- const [index, setIndex] = useState23(null);
7152
- const startRequestedRef = useRef19(false);
7153
- useEffect29(() => {
7362
+ const [index, setIndex] = useState24(null);
7363
+ const startRequestedRef = useRef20(false);
7364
+ useEffect30(() => {
7154
7365
  setIndex(null);
7155
7366
  startRequestedRef.current = false;
7156
7367
  if (!providerV2 || !workspaceId) return;
@@ -7172,7 +7383,7 @@ function useWorkspaceIndex(provider, workspaceId, mode = "eager") {
7172
7383
  created?.dispose();
7173
7384
  };
7174
7385
  }, [providerV2, workspaceId, mode]);
7175
- useEffect29(() => {
7386
+ useEffect30(() => {
7176
7387
  if (!index) return;
7177
7388
  const refresh = () => index.refresh();
7178
7389
  const onVisibilityChange = () => {
@@ -7404,6 +7615,47 @@ async function copyTransientWorkspaceContents(source, destination) {
7404
7615
  }
7405
7616
  }
7406
7617
 
7618
+ // src/DocBlocksShell/document-relative-media.ts
7619
+ import {
7620
+ FileSystemContentContainer as FileSystemContentContainer2,
7621
+ isDocumentMediaPath,
7622
+ resolveDocumentRelativeMediaPath,
7623
+ tryParseWorkspacePath as tryParseWorkspacePath5
7624
+ } from "@bendyline/docblocks/filesystem";
7625
+ import { hostSupports as hostSupports2, maybeGetDocBlocksHost as maybeGetDocBlocksHost4 } from "@bendyline/docblocks/host";
7626
+ import { getTransientWorkspace } from "@bendyline/docblocks/workspace";
7627
+ function looseFileMediaReader(workspaceId) {
7628
+ const origin = getTransientWorkspace(workspaceId)?.descriptor.origin;
7629
+ if (origin?.kind !== "loose-file" || !hostSupports2("externalRelativeMedia")) return null;
7630
+ const external = maybeGetDocBlocksHost4()?.external;
7631
+ if (!external?.readRelativeMedia) return null;
7632
+ const { resourceId } = origin;
7633
+ return async (path) => await external.readRelativeMedia?.(resourceId, path) ?? null;
7634
+ }
7635
+ var LooseFileMediaContainer = class extends FileSystemContentContainer2 {
7636
+ constructor(provider, directory, readBeside) {
7637
+ super(provider, directory);
7638
+ this.directory = directory;
7639
+ this.readBeside = readBeside;
7640
+ }
7641
+ async readFile(path) {
7642
+ const data = await super.readFile(path);
7643
+ if (data) return data;
7644
+ const beside = tryParseWorkspacePath5(this.directory ? `${this.directory}/${path}` : path);
7645
+ if (!beside || !isDocumentMediaPath(beside)) return null;
7646
+ return this.readBeside(beside).catch(() => null);
7647
+ }
7648
+ };
7649
+ function createMediaContainer(provider, directory, readBesideLooseFile) {
7650
+ return readBesideLooseFile ? new LooseFileMediaContainer(provider, directory, readBesideLooseFile) : new FileSystemContentContainer2(provider, directory);
7651
+ }
7652
+ function createDocumentRelativeMediaReader(root, documentDirectory) {
7653
+ return async (ref) => {
7654
+ const path = resolveDocumentRelativeMediaPath(documentDirectory, ref);
7655
+ return path === null ? null : root.readFile(path);
7656
+ };
7657
+ }
7658
+
7407
7659
  // src/DocBlocksShell/native-file-actions.ts
7408
7660
  function createNativeFileActions(entry, workspaceId, host) {
7409
7661
  if (entry.kind !== "file" || workspaceId === null || host === null) return [];
@@ -7507,7 +7759,7 @@ var WELCOME_DOCUMENT_CONTENT = welcomeDocumentContent({
7507
7759
  });
7508
7760
 
7509
7761
  // src/DocBlocksShell/DocBlocksShell.tsx
7510
- import { Fragment as Fragment11, jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
7762
+ import { Fragment as Fragment12, jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
7511
7763
  var editorShellModulePromise = null;
7512
7764
  function loadEditorShell() {
7513
7765
  editorShellModulePromise ?? (editorShellModulePromise = (async () => {
@@ -7519,13 +7771,13 @@ function loadEditorShell() {
7519
7771
  return editorShellModulePromise;
7520
7772
  }
7521
7773
  var EditorShell = lazy2(loadEditorShell);
7522
- var DocumentConflictDialog = lazy2(() => import("./DocumentConflictDialog-DZ2BV2IH.js"));
7523
- var GitUI = lazy2(() => import("./GitUI-F3CNBURE.js").then((m) => ({ default: m.GitUI })));
7774
+ var DocumentConflictDialog = lazy2(() => import("./DocumentConflictDialog-4R4QMKBT.js"));
7775
+ var GitUI = lazy2(() => import("./GitUI-3FANM7I3.js").then((m) => ({ default: m.GitUI })));
7524
7776
  var QuickOpenDialog = lazy2(
7525
- () => import("./QuickOpenDialog-3QEX7RZG.js").then((m) => ({ default: m.QuickOpenDialog }))
7777
+ () => import("./QuickOpenDialog-U2FWCEPA.js").then((m) => ({ default: m.QuickOpenDialog }))
7526
7778
  );
7527
7779
  var KeyboardShortcutsDialog = lazy2(
7528
- () => import("./KeyboardShortcutsDialog-HVKDFP5Z.js").then((m) => ({ default: m.KeyboardShortcutsDialog }))
7780
+ () => import("./KeyboardShortcutsDialog-7XJTDIX2.js").then((m) => ({ default: m.KeyboardShortcutsDialog }))
7529
7781
  );
7530
7782
  var WorkspaceSearchPanel = lazy2(
7531
7783
  () => import("./WorkspaceSearchPanel-MEBBTK7F.js").then((m) => ({
@@ -7539,37 +7791,42 @@ var GitToolbarControl = lazy2(
7539
7791
  () => import("./GitToolbarControl-B7KG4MFP.js").then((m) => ({ default: m.GitToolbarControl }))
7540
7792
  );
7541
7793
  var AiToolbarControl = lazy2(
7542
- () => import("./AiEditorAssistant-2MW6UYNI.js").then((module) => ({
7794
+ () => import("./AiEditorAssistant-ANYGVG7P.js").then((module) => ({
7543
7795
  default: module.AiToolbarControl
7544
7796
  }))
7545
7797
  );
7546
7798
  var PresentationMaker = lazy2(
7547
- () => import("./PresentationMaker-T526TBRJ.js").then((module) => ({
7799
+ () => import("./PresentationMaker-COLTVMTS.js").then((module) => ({
7548
7800
  default: module.PresentationMaker
7549
7801
  }))
7550
7802
  );
7551
7803
  var AiReviewPanel = lazy2(
7552
- () => import("./AiEditorAssistant-2MW6UYNI.js").then((module) => ({
7804
+ () => import("./AiEditorAssistant-ANYGVG7P.js").then((module) => ({
7553
7805
  default: module.AiReviewPanel
7554
7806
  }))
7555
7807
  );
7556
7808
  var AiIllustratePanel = lazy2(
7557
- () => import("./AiDiagrams-VOCEZS6U.js").then((module) => ({
7809
+ () => import("./AiDiagrams-2IKKSBAU.js").then((module) => ({
7558
7810
  default: module.AiIllustratePanel
7559
7811
  }))
7560
7812
  );
7813
+ var AiImagePanel = lazy2(
7814
+ () => import("./AiImagePanel-OXWEFOBC.js").then((module) => ({
7815
+ default: module.AiImagePanel
7816
+ }))
7817
+ );
7561
7818
  var TextFromNarration = lazy2(
7562
- () => import("./TextFromNarration-ME6FAYWO.js").then((module) => ({
7819
+ () => import("./TextFromNarration-6BYTUKVZ.js").then((module) => ({
7563
7820
  default: module.TextFromNarration
7564
7821
  }))
7565
7822
  );
7566
7823
  var SpeechToolbarControl = lazy2(
7567
- () => import("./SpeechToolbarControl-E6OSJGHL.js").then((module) => ({
7824
+ () => import("./SpeechToolbarControl-BZW6IVZM.js").then((module) => ({
7568
7825
  default: module.SpeechToolbarControl
7569
7826
  }))
7570
7827
  );
7571
7828
  var SpeechMenuBridge = lazy2(
7572
- () => import("./SpeechToolbarControl-E6OSJGHL.js").then((module) => ({
7829
+ () => import("./SpeechToolbarControl-BZW6IVZM.js").then((module) => ({
7573
7830
  default: module.SpeechMenuBridge
7574
7831
  }))
7575
7832
  );
@@ -7647,10 +7904,10 @@ function isMemoryWorkspaceProvider(provider) {
7647
7904
  return typeof candidate.captureContents === "function" && typeof candidate.replaceContents === "function" && typeof candidate.treeVersion === "number";
7648
7905
  }
7649
7906
  function useOsTheme() {
7650
- const [dark, setDark] = useState24(
7907
+ const [dark, setDark] = useState25(
7651
7908
  () => typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches
7652
7909
  );
7653
- useEffect30(() => {
7910
+ useEffect31(() => {
7654
7911
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
7655
7912
  const handler = (e) => setDark(e.matches);
7656
7913
  mq.addEventListener("change", handler);
@@ -7836,7 +8093,7 @@ async function createHostProviderFromWorkspace(ws) {
7836
8093
  var DESKTOP_TOOLBAR_WRAP_WIDTH = 900;
7837
8094
  var WEB_TOOLBAR_WRAP_WIDTH = 700;
7838
8095
  function FolderGlyph() {
7839
- return /* @__PURE__ */ jsx19(
8096
+ return /* @__PURE__ */ jsx21(
7840
8097
  "svg",
7841
8098
  {
7842
8099
  viewBox: "0 0 24 24",
@@ -7845,12 +8102,12 @@ function FolderGlyph() {
7845
8102
  strokeWidth: "1.5",
7846
8103
  strokeLinejoin: "round",
7847
8104
  "aria-hidden": "true",
7848
- children: /* @__PURE__ */ jsx19("path", { d: "M3 7a1 1 0 0 1 1-1h5l2 2h9a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7z" })
8105
+ children: /* @__PURE__ */ jsx21("path", { d: "M3 7a1 1 0 0 1 1-1h5l2 2h9a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7z" })
7849
8106
  }
7850
8107
  );
7851
8108
  }
7852
8109
  function FileGlyph() {
7853
- return /* @__PURE__ */ jsxs17(
8110
+ return /* @__PURE__ */ jsxs19(
7854
8111
  "svg",
7855
8112
  {
7856
8113
  viewBox: "0 0 24 24",
@@ -7860,14 +8117,14 @@ function FileGlyph() {
7860
8117
  strokeLinejoin: "round",
7861
8118
  "aria-hidden": "true",
7862
8119
  children: [
7863
- /* @__PURE__ */ jsx19("path", { d: "M6 3h8l5 5v12a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z" }),
7864
- /* @__PURE__ */ jsx19("path", { d: "M14 3v5h5" })
8120
+ /* @__PURE__ */ jsx21("path", { d: "M6 3h8l5 5v12a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z" }),
8121
+ /* @__PURE__ */ jsx21("path", { d: "M14 3v5h5" })
7865
8122
  ]
7866
8123
  }
7867
8124
  );
7868
8125
  }
7869
8126
  function CollapseSidebarGlyph() {
7870
- return /* @__PURE__ */ jsxs17(
8127
+ return /* @__PURE__ */ jsxs19(
7871
8128
  "svg",
7872
8129
  {
7873
8130
  viewBox: "0 0 64 64",
@@ -7878,9 +8135,9 @@ function CollapseSidebarGlyph() {
7878
8135
  strokeLinejoin: "round",
7879
8136
  "aria-hidden": "true",
7880
8137
  children: [
7881
- /* @__PURE__ */ jsx19("rect", { x: "7", y: "10", width: "50", height: "44", rx: "6" }),
7882
- /* @__PURE__ */ jsx19("path", { d: "M24 10v44" }),
7883
- /* @__PURE__ */ jsx19("path", { d: "m17 25-7 7 7 7" })
8138
+ /* @__PURE__ */ jsx21("rect", { x: "7", y: "10", width: "50", height: "44", rx: "6" }),
8139
+ /* @__PURE__ */ jsx21("path", { d: "M24 10v44" }),
8140
+ /* @__PURE__ */ jsx21("path", { d: "m17 25-7 7 7 7" })
7884
8141
  ]
7885
8142
  }
7886
8143
  );
@@ -7917,10 +8174,10 @@ function DocBlocksShell({
7917
8174
  offlineReady = false
7918
8175
  }) {
7919
8176
  const osTheme = useOsTheme();
7920
- const [themePreference, setThemePreference] = useState24(loadThemePreference);
7921
- const [accentColor, setAccentColor] = useState24(loadAccentColor);
7922
- const [interfaceFont, setInterfaceFont] = useState24(loadInterfaceFont);
7923
- const [writeCanvasSettings, setWriteCanvasSettings] = useState24(
8177
+ const [themePreference, setThemePreference] = useState25(loadThemePreference);
8178
+ const [accentColor, setAccentColor] = useState25(loadAccentColor);
8179
+ const [interfaceFont, setInterfaceFont] = useState25(loadInterfaceFont);
8180
+ const [writeCanvasSettings, setWriteCanvasSettings] = useState25(
7924
8181
  loadWriteCanvasPreferences
7925
8182
  );
7926
8183
  const editorWriteCanvasSettings = useMemo6(
@@ -7932,21 +8189,28 @@ function DocBlocksShell({
7932
8189
  [writeCanvasSettings]
7933
8190
  );
7934
8191
  const resolvedTheme = resolveShellTheme({ preference: themePreference, hostTheme, osTheme });
7935
- const ai = hostSupports2("aiAssist") ? maybeGetDocBlocksHost4()?.ai : void 0;
7936
- const speech = hostSupports2("speechModelManagement") ? maybeGetDocBlocksHost4()?.speech : void 0;
7937
- const trayMenu = hostSupports2("trayIcon") ? maybeGetDocBlocksHost4()?.menu : void 0;
7938
- const [settingsRequest, setSettingsRequest] = useState24(0);
7939
- const openSettings = useCallback19(() => setSettingsRequest((count) => count + 1), []);
8192
+ const ai = hostSupports3("aiAssist") ? maybeGetDocBlocksHost5()?.ai : void 0;
8193
+ const speech = hostSupports3("speechModelManagement") ? maybeGetDocBlocksHost5()?.speech : void 0;
8194
+ const trayMenu = hostSupports3("trayIcon") ? maybeGetDocBlocksHost5()?.menu : void 0;
8195
+ const [settingsRequest, setSettingsRequest] = useState25({ count: 0 });
8196
+ const openDictationSettings = useCallback19(
8197
+ () => setSettingsRequest(({ count }) => ({ count: count + 1, section: "dictation" })),
8198
+ []
8199
+ );
8200
+ const openNarrationSettings = useCallback19(
8201
+ () => setSettingsRequest(({ count }) => ({ count: count + 1, section: "narration" })),
8202
+ []
8203
+ );
7940
8204
  const speechInput = useMemo6(
7941
- () => speech && hostSupports2("speechInput") ? createSpeechInputProvider(speech, { onRequestSetup: openSettings }) : null,
7942
- [speech, openSettings]
8205
+ () => speech && hostSupports3("speechInput") ? createSpeechInputProvider(speech, { onRequestSetup: openDictationSettings }) : null,
8206
+ [speech, openDictationSettings]
7943
8207
  );
7944
8208
  const handleThemeChange = useCallback19((pref) => {
7945
8209
  setThemePreference(pref);
7946
8210
  saveThemePreference(pref);
7947
8211
  }, []);
7948
- useEffect30(() => {
7949
- if (hostSupports2("ownsWindowChrome") || typeof document === "undefined") return;
8212
+ useEffect31(() => {
8213
+ if (hostSupports3("ownsWindowChrome") || typeof document === "undefined") return;
7950
8214
  const metas = document.querySelectorAll('meta[name="theme-color"]');
7951
8215
  metas.forEach((meta) => {
7952
8216
  meta.content = DB_CHROME_COLORS[resolvedTheme];
@@ -7960,19 +8224,19 @@ function DocBlocksShell({
7960
8224
  setWriteCanvasSettings(settings);
7961
8225
  saveWriteCanvasPreferences(settings);
7962
8226
  }, []);
7963
- const [proofingPreferences, setProofingPreferences] = useState24(loadProofingPreferences);
8227
+ const [proofingPreferences, setProofingPreferences] = useState25(loadProofingPreferences);
7964
8228
  const handleProofingPreferencesChange = useCallback19((settings) => {
7965
8229
  setProofingPreferences(settings);
7966
8230
  saveProofingPreferences(settings);
7967
8231
  }, []);
7968
- const [viewPreferences, setViewPreferences] = useState24(loadViewPreferences);
8232
+ const [viewPreferences, setViewPreferences] = useState25(loadViewPreferences);
7969
8233
  const handleViewPreferencesChange = useCallback19((prefs) => {
7970
8234
  setViewPreferences(prefs);
7971
8235
  saveViewPreferences(prefs);
7972
8236
  }, []);
7973
- const shellRef = useRef20(null);
8237
+ const shellRef = useRef21(null);
7974
8238
  const formFactor = useFormFactor(shellRef);
7975
- const [sidebarPreference, setSidebarPreference] = useState24(loadSidebarPreference);
8239
+ const [sidebarPreference, setSidebarPreference] = useState25(loadSidebarPreference);
7976
8240
  const layoutMode = resolveLayoutMode(formFactor, sidebarPreference);
7977
8241
  const singlePane = layoutMode === "single-pane";
7978
8242
  const updateSidebarPreference = useCallback19((preference) => {
@@ -7980,27 +8244,27 @@ function DocBlocksShell({
7980
8244
  saveSidebarPreference(preference);
7981
8245
  }, []);
7982
8246
  const defaultPreviewViewportPreset = useResponsivePreviewViewportPreset();
7983
- const [mobileShowEditor, setMobileShowEditor] = useState24(
8247
+ const [mobileShowEditor, setMobileShowEditor] = useState25(
7984
8248
  () => singlePane && isWelcomeGatewayDismissed()
7985
8249
  );
7986
- useEffect30(() => {
8250
+ useEffect31(() => {
7987
8251
  if (singlePane) void loadEditorShell();
7988
8252
  }, [singlePane]);
7989
8253
  useFormFactorAttributes(shellRef, formFactor, layoutMode, !mobileShowEditor);
7990
8254
  useInterfaceFontAttribute(interfaceFont);
7991
8255
  useKeyboardInset(formFactor.pointer === "coarse");
7992
8256
  const drawerOpen = singlePane && !mobileShowEditor;
7993
- const [sidebarWidth, setSidebarWidth] = useState24(loadSidebarWidth);
8257
+ const [sidebarWidth, setSidebarWidth] = useState25(loadSidebarWidth);
7994
8258
  const canRestoreSplitView = sidebarPreference === "collapsed" && formFactor.splitPaneAllowed;
7995
- const editorAreaRef = useRef20(null);
7996
- const [desktopToolbarWrapped, setDesktopToolbarWrapped] = useState24(false);
7997
- useEffect30(() => {
8259
+ const editorAreaRef = useRef21(null);
8260
+ const [desktopToolbarWrapped, setDesktopToolbarWrapped] = useState25(false);
8261
+ useEffect31(() => {
7998
8262
  const editorArea = editorAreaRef.current;
7999
8263
  if (!editorArea || singlePane) {
8000
8264
  setDesktopToolbarWrapped(false);
8001
8265
  return;
8002
8266
  }
8003
- const wrapWidth = hostSupports2("ownsWindowChrome") ? DESKTOP_TOOLBAR_WRAP_WIDTH : WEB_TOOLBAR_WRAP_WIDTH;
8267
+ const wrapWidth = hostSupports3("ownsWindowChrome") ? DESKTOP_TOOLBAR_WRAP_WIDTH : WEB_TOOLBAR_WRAP_WIDTH;
8004
8268
  const updateWrappedState = () => {
8005
8269
  setDesktopToolbarWrapped(editorArea.getBoundingClientRect().width <= wrapWidth);
8006
8270
  };
@@ -8013,8 +8277,8 @@ function DocBlocksShell({
8013
8277
  observer.observe(editorArea);
8014
8278
  return () => observer.disconnect();
8015
8279
  }, [singlePane]);
8016
- const showBrowserStorageWarning = hostSupports2("browserOriginStorage");
8017
- const hostEnvironment = getHostEnvironment2();
8280
+ const showBrowserStorageWarning = hostSupports3("browserOriginStorage");
8281
+ const hostEnvironment = getHostEnvironment3();
8018
8282
  const desktopApp = hostEnvironment?.surface === "electron";
8019
8283
  const appVersion = hostEnvironment ? `${hostEnvironment.appVersion} ${hostEnvironment.surfaceLabel}` : issueReportVersion ?? "web";
8020
8284
  const issueReportUrl = buildIssueReportUrl({
@@ -8022,16 +8286,16 @@ function DocBlocksShell({
8022
8286
  version: appVersion,
8023
8287
  userAgent: typeof navigator === "undefined" ? "" : navigator.userAgent
8024
8288
  });
8025
- const [browserStoragePersistent, setBrowserStoragePersistent] = useState24(false);
8026
- const [saveToast, setSaveToast] = useState24(null);
8027
- const saveToastTimerRef = useRef20(null);
8289
+ const [browserStoragePersistent, setBrowserStoragePersistent] = useState25(false);
8290
+ const [saveToast, setSaveToast] = useState25(null);
8291
+ const saveToastTimerRef = useRef21(null);
8028
8292
  const showToast = useCallback19((kind, message) => {
8029
8293
  setSaveToast({ kind, message });
8030
8294
  if (saveToastTimerRef.current) clearTimeout(saveToastTimerRef.current);
8031
8295
  saveToastTimerRef.current = setTimeout(() => setSaveToast(null), 3e3);
8032
8296
  }, []);
8033
8297
  const { prompt: promptForText, promptDialog } = usePromptDialog();
8034
- const [newDocumentDialogOpen, setNewDocumentDialogOpen] = useState24(false);
8298
+ const [newDocumentDialogOpen, setNewDocumentDialogOpen] = useState25(false);
8035
8299
  const { confirm: confirmAction, acknowledge, confirmDialog } = useConfirmDialog();
8036
8300
  const confirmDeleteEntry = useCallback19(
8037
8301
  (message) => confirmAction({
@@ -8042,11 +8306,11 @@ function DocBlocksShell({
8042
8306
  }),
8043
8307
  [confirmAction]
8044
8308
  );
8045
- const [installPromptEvent, setInstallPromptEvent] = useState24(
8309
+ const [installPromptEvent, setInstallPromptEvent] = useState25(
8046
8310
  null
8047
8311
  );
8048
- const panesRef = useRef20(null);
8049
- const sidebarRef = useRef20(null);
8312
+ const panesRef = useRef21(null);
8313
+ const sidebarRef = useRef21(null);
8050
8314
  useInert(sidebarRef, singlePane && !drawerOpen);
8051
8315
  useInert(editorAreaRef, drawerOpen);
8052
8316
  const openDrawer = useCallback19(() => setMobileShowEditor(false), []);
@@ -8059,7 +8323,7 @@ function DocBlocksShell({
8059
8323
  onOpen: openDrawer,
8060
8324
  onClose: closeDrawer
8061
8325
  });
8062
- const dragStateRef = useRef20(null);
8326
+ const dragStateRef = useRef21(null);
8063
8327
  const handleResizerPointerDown = useCallback19(
8064
8328
  (e) => {
8065
8329
  if (e.button !== 0) return;
@@ -8112,36 +8376,36 @@ function DocBlocksShell({
8112
8376
  },
8113
8377
  [sidebarWidth, updateSidebarPreference]
8114
8378
  );
8115
- const [provider, setProvider] = useState24(null);
8116
- const [workspaceStartupError, setWorkspaceStartupError] = useState24(null);
8379
+ const [provider, setProvider] = useState25(null);
8380
+ const [workspaceStartupError, setWorkspaceStartupError] = useState25(null);
8117
8381
  const workspaceStarting = provider === null && workspaceStartupError === null;
8118
- const [activeWorkspaceId, setActiveWorkspaceId] = useState24(null);
8119
- const [defaultNewFileFormat, setDefaultNewFileFormat] = useState24(DEFAULT_NEW_FILE_FORMAT);
8120
- useEffect30(() => {
8382
+ const [activeWorkspaceId, setActiveWorkspaceId] = useState25(null);
8383
+ const [defaultNewFileFormat, setDefaultNewFileFormat] = useState25(DEFAULT_NEW_FILE_FORMAT);
8384
+ useEffect31(() => {
8121
8385
  setDefaultNewFileFormat(loadLastNewFileFormat(activeWorkspaceId));
8122
8386
  }, [activeWorkspaceId]);
8123
8387
  const rememberNewFileFormat = useCallback19(
8124
8388
  (format) => {
8125
8389
  setDefaultNewFileFormat(format);
8126
- if (activeWorkspaceId && getTransientWorkspace(activeWorkspaceId) === null) {
8390
+ if (activeWorkspaceId && getTransientWorkspace2(activeWorkspaceId) === null) {
8127
8391
  saveLastNewFileFormat(activeWorkspaceId, format);
8128
8392
  }
8129
8393
  },
8130
8394
  [activeWorkspaceId]
8131
8395
  );
8132
- const [activeWorkspaceDescriptor, setActiveWorkspaceDescriptor] = useState24(null);
8396
+ const [activeWorkspaceDescriptor, setActiveWorkspaceDescriptor] = useState25(null);
8133
8397
  const defaultProofingIgnoreStore = useMemo6(
8134
8398
  () => createLocalProofingIgnoreStore(() => activeWorkspaceId),
8135
8399
  [activeWorkspaceId]
8136
8400
  );
8137
8401
  const effectiveProofingIgnoreStore = proofingIgnoreStore === void 0 ? defaultProofingIgnoreStore : proofingIgnoreStore;
8138
- useEffect30(() => {
8139
- if (!provider || getTransientWorkspace(provider.id)) return;
8402
+ useEffect31(() => {
8403
+ if (!provider || getTransientWorkspace2(provider.id)) return;
8140
8404
  const providerV2 = getFileSystemProviderV211(provider);
8141
8405
  return providerV2 ? retainFileSystemProvider(providerV2) : void 0;
8142
8406
  }, [provider]);
8143
- const [descriptorRefreshKey, setDescriptorRefreshKey] = useState24(0);
8144
- useEffect30(() => {
8407
+ const [descriptorRefreshKey, setDescriptorRefreshKey] = useState25(0);
8408
+ useEffect31(() => {
8145
8409
  let cancelled = false;
8146
8410
  if (!activeWorkspaceId) {
8147
8411
  setActiveWorkspaceDescriptor(null);
@@ -8154,14 +8418,14 @@ function DocBlocksShell({
8154
8418
  cancelled = true;
8155
8419
  };
8156
8420
  }, [activeWorkspaceId, descriptorRefreshKey]);
8157
- const [pinnedDocuments, setPinnedDocuments] = useState24(loadPinnedDocuments);
8158
- const [pinnedDocumentAvailability, setPinnedDocumentAvailability] = useState24(() => /* @__PURE__ */ new Map());
8159
- useEffect30(() => {
8421
+ const [pinnedDocuments, setPinnedDocuments] = useState25(loadPinnedDocuments);
8422
+ const [pinnedDocumentAvailability, setPinnedDocumentAvailability] = useState25(() => /* @__PURE__ */ new Map());
8423
+ useEffect31(() => {
8160
8424
  savePinnedDocuments(pinnedDocuments);
8161
8425
  }, [pinnedDocuments]);
8162
- useEffect30(() => {
8163
- const menu = maybeGetDocBlocksHost4()?.menu;
8164
- if (!hostSupports2("pinnedDocumentMirror") || !menu) return;
8426
+ useEffect31(() => {
8427
+ const menu = maybeGetDocBlocksHost5()?.menu;
8428
+ if (!hostSupports3("pinnedDocumentMirror") || !menu) return;
8165
8429
  menu.setPinnedDocuments(
8166
8430
  pinnedDocuments.map((document2) => ({
8167
8431
  workspaceId: document2.workspaceId,
@@ -8189,7 +8453,7 @@ function DocBlocksShell({
8189
8453
  })),
8190
8454
  [pinnedDocumentAvailability, pinnedDocuments]
8191
8455
  );
8192
- useEffect30(() => {
8456
+ useEffect31(() => {
8193
8457
  if (!provider || !activeWorkspaceId) return;
8194
8458
  const activePins = pinnedDocuments.filter(
8195
8459
  (document2) => document2.workspaceId === activeWorkspaceId
@@ -8239,16 +8503,16 @@ function DocBlocksShell({
8239
8503
  void subscription?.dispose();
8240
8504
  };
8241
8505
  }, [activeWorkspaceId, pinnedDocuments, provider, setPinnedAvailability]);
8242
- const [transientMoveDestinations, setTransientMoveDestinations] = useState24(
8506
+ const [transientMoveDestinations, setTransientMoveDestinations] = useState25(
8243
8507
  []
8244
8508
  );
8245
- useEffect30(() => {
8509
+ useEffect31(() => {
8246
8510
  if (activeWorkspaceDescriptor?.type !== "transient") {
8247
8511
  setTransientMoveDestinations([]);
8248
8512
  return;
8249
8513
  }
8250
8514
  let cancelled = false;
8251
- const electron = hostSupports2("nativeWorkspaces");
8515
+ const electron = hostSupports3("nativeWorkspaces");
8252
8516
  void listWorkspaces2().then((workspaces) => {
8253
8517
  if (cancelled) return;
8254
8518
  setTransientMoveDestinations(
@@ -8264,19 +8528,19 @@ function DocBlocksShell({
8264
8528
  };
8265
8529
  }, [activeWorkspaceDescriptor]);
8266
8530
  const nativeWorkspaceId = provider && activeWorkspaceDescriptor?.id === activeWorkspaceId && provider.id === activeWorkspaceId && activeWorkspaceDescriptor.type === "host-native" ? activeWorkspaceDescriptor.id : null;
8267
- const workingTreeChangedRef = useRef20(() => void 0);
8531
+ const workingTreeChangedRef = useRef21(() => void 0);
8268
8532
  const handleWorkingTreeChanged = useCallback19(() => workingTreeChangedRef.current(), []);
8269
8533
  const git = useGit(provider, nativeWorkspaceId, resolvedTheme, handleWorkingTreeChanged);
8270
- const gitRef = useRef20(git);
8534
+ const gitRef = useRef21(git);
8271
8535
  gitRef.current = git;
8272
8536
  const { scheduleRefresh: gitScheduleRefresh } = git;
8273
- const workspaceSettingsEnabled = provider !== null && provider.id === activeWorkspaceId && getTransientWorkspace(provider.id) === null;
8537
+ const workspaceSettingsEnabled = provider !== null && provider.id === activeWorkspaceId && getTransientWorkspace2(provider.id) === null;
8274
8538
  const workspaceSettings = useWorkspaceSettings(provider, workspaceSettingsEnabled);
8275
8539
  const { refresh: refreshWorkspaceSettings, save: saveWorkspaceSettings } = workspaceSettings;
8276
8540
  const workspaceDefaultThemeId = resolveWorkspaceDefaultThemeId(workspaceSettings.settings);
8277
- const workspaceDefaultThemeRef = useRef20(workspaceDefaultThemeId);
8541
+ const workspaceDefaultThemeRef = useRef21(workspaceDefaultThemeId);
8278
8542
  workspaceDefaultThemeRef.current = workspaceDefaultThemeId;
8279
- const outsideInRenderRef = useRef20({
8543
+ const outsideInRenderRef = useRef21({
8280
8544
  defaultThemeId: () => workspaceDefaultThemeRef.current
8281
8545
  });
8282
8546
  const workspaceOutputs = useWorkspaceOutputs(
@@ -8285,10 +8549,10 @@ function DocBlocksShell({
8285
8549
  workspaceSettings.settings,
8286
8550
  workspaceSettingsEnabled
8287
8551
  );
8288
- const workspaceOutputsSchedulerRef = useRef20(workspaceOutputs.scheduler);
8552
+ const workspaceOutputsSchedulerRef = useRef21(workspaceOutputs.scheduler);
8289
8553
  workspaceOutputsSchedulerRef.current = workspaceOutputs.scheduler;
8290
8554
  const workspaceIndex = useWorkspaceIndex(provider, activeWorkspaceId, workspaceIndexMode);
8291
- const workspaceIndexRef = useRef20(workspaceIndex.index);
8555
+ const workspaceIndexRef = useRef21(workspaceIndex.index);
8292
8556
  workspaceIndexRef.current = workspaceIndex.index;
8293
8557
  const notifyWorkspaceChanged = useCallback19(
8294
8558
  (workspaceId, path) => {
@@ -8307,8 +8571,8 @@ function DocBlocksShell({
8307
8571
  workspaceOutputsSchedulerRef.current?.notify();
8308
8572
  workspaceIndexRef.current?.refresh({ force: true });
8309
8573
  };
8310
- const [workspaceSettingsOpen, setWorkspaceSettingsOpen] = useState24(false);
8311
- const [versioningPreference, setVersioningPreference] = useState24(loadVersioningPreference);
8574
+ const [workspaceSettingsOpen, setWorkspaceSettingsOpen] = useState25(false);
8575
+ const [versioningPreference, setVersioningPreference] = useState25(loadVersioningPreference);
8312
8576
  const handleVersioningPreferenceChange = useCallback19((pref) => {
8313
8577
  setVersioningPreference(pref);
8314
8578
  saveVersioningPreference(pref);
@@ -8343,16 +8607,16 @@ function DocBlocksShell({
8343
8607
  const handleRegenerateWorkspaceOutputs = useCallback19(() => {
8344
8608
  void workspaceOutputsSchedulerRef.current?.regenerate({ force: true });
8345
8609
  }, []);
8346
- const [selectedFile, setSelectedFile] = useState24(null);
8347
- const [selectedSourceFile, setSelectedSourceFile] = useState24(null);
8348
- const [selectedOutsideIn, setSelectedOutsideIn] = useState24(null);
8349
- const [selectedOutsideInEditingEnabled, setSelectedOutsideInEditingEnabled] = useState24(false);
8350
- const [selectedImage, setSelectedImage] = useState24(void 0);
8351
- const [selectedManagedOutput, setSelectedManagedOutput] = useState24(void 0);
8352
- const [findMode, setFindMode] = useState24(false);
8353
- const findModeRef = useRef20(findMode);
8610
+ const [selectedFile, setSelectedFile] = useState25(null);
8611
+ const [selectedSourceFile, setSelectedSourceFile] = useState25(null);
8612
+ const [selectedOutsideIn, setSelectedOutsideIn] = useState25(null);
8613
+ const [selectedOutsideInEditingEnabled, setSelectedOutsideInEditingEnabled] = useState25(false);
8614
+ const [selectedImage, setSelectedImage] = useState25(void 0);
8615
+ const [selectedManagedOutput, setSelectedManagedOutput] = useState25(void 0);
8616
+ const [findMode, setFindMode] = useState25(false);
8617
+ const findModeRef = useRef21(findMode);
8354
8618
  findModeRef.current = findMode;
8355
- useEffect30(() => {
8619
+ useEffect31(() => {
8356
8620
  setFindMode(false);
8357
8621
  }, [selectedFile]);
8358
8622
  const openFind = useCallback19(() => {
@@ -8364,16 +8628,16 @@ function DocBlocksShell({
8364
8628
  }, []);
8365
8629
  const findShortcut = useMemo6(findShortcutLabel, []);
8366
8630
  const searchShortcut = useMemo6(() => shortcutLabel("workspace-search", isApplePlatform()), []);
8367
- const [quickOpenOpen, setQuickOpenOpen] = useState24(false);
8368
- const [shortcutsOpen, setShortcutsOpen] = useState24(false);
8631
+ const [quickOpenOpen, setQuickOpenOpen] = useState25(false);
8632
+ const [shortcutsOpen, setShortcutsOpen] = useState25(false);
8369
8633
  const openKeyboardShortcuts = useCallback19(() => setShortcutsOpen(true), []);
8370
- const [quickOpenFocusRequest, setQuickOpenFocusRequest] = useState24(0);
8371
- const [sidebarView, setSidebarView] = useState24("files");
8372
- const [searchMounted, setSearchMounted] = useState24(false);
8373
- const [searchFocusRequest, setSearchFocusRequest] = useState24(0);
8374
- useEffect30(() => {
8634
+ const [quickOpenFocusRequest, setQuickOpenFocusRequest] = useState25(0);
8635
+ const [sidebarView, setSidebarView] = useState25("files");
8636
+ const [searchMounted, setSearchMounted] = useState25(false);
8637
+ const [searchFocusRequest, setSearchFocusRequest] = useState25(0);
8638
+ useEffect31(() => {
8375
8639
  if (!activeWorkspaceId || !selectedFile) return;
8376
- if (getTransientWorkspace(activeWorkspaceId) === null) {
8640
+ if (getTransientWorkspace2(activeWorkspaceId) === null) {
8377
8641
  recordRecentDocument(activeWorkspaceId, selectedFile);
8378
8642
  }
8379
8643
  workspaceIndex.index?.prioritize([selectedFile]);
@@ -8413,7 +8677,7 @@ function DocBlocksShell({
8413
8677
  }
8414
8678
  return URL.createObjectURL(new Blob([selectedImage.data], { type: selectedImage.mimeType }));
8415
8679
  }, [selectedImage]);
8416
- useEffect30(
8680
+ useEffect31(
8417
8681
  () => () => {
8418
8682
  if (selectedImageUrl) URL.revokeObjectURL(selectedImageUrl);
8419
8683
  },
@@ -8422,8 +8686,8 @@ function DocBlocksShell({
8422
8686
  useDocumentTitle(selectedFile, homeDocumentTitle, homeDocumentPath);
8423
8687
  const exportDestinationAdapter = useMemo6(() => {
8424
8688
  if (!selectedFile) return void 0;
8425
- const exports = maybeGetDocBlocksHost4()?.exports;
8426
- if (hostSupports2("exportRememberedTargets") && exports?.resolveTarget && exports.pickTarget) {
8689
+ const exports = maybeGetDocBlocksHost5()?.exports;
8690
+ if (hostSupports3("exportRememberedTargets") && exports?.resolveTarget && exports.pickTarget) {
8427
8691
  if (activeWorkspaceId) {
8428
8692
  const documentId = JSON.stringify([activeWorkspaceId, selectedFile]);
8429
8693
  const resolveTarget = exports.resolveTarget.bind(exports);
@@ -8432,7 +8696,7 @@ function DocBlocksShell({
8432
8696
  resolveTarget: (filename) => resolveTarget(documentId, filename),
8433
8697
  pickTarget: (filename, currentTarget) => pickTarget(documentId, filename, currentTarget?.grantId ?? null),
8434
8698
  saveBlob: (blob, filename, target) => saveBlobToHost(exports, documentId, blob, filename, target?.grantId ?? null),
8435
- ...hostSupports2("openSavedExports") && exports.openSaved ? {
8699
+ ...hostSupports3("openSavedExports") && exports.openSaved ? {
8436
8700
  openSaved: async (target) => {
8437
8701
  if (!target.grantId) throw new Error("The saved export has no native target.");
8438
8702
  await exports.openSaved(documentId, target.grantId);
@@ -8441,7 +8705,7 @@ function DocBlocksShell({
8441
8705
  };
8442
8706
  }
8443
8707
  }
8444
- if (hostSupports2("exportDestinations") && exports && activeWorkspaceId) {
8708
+ if (hostSupports3("exportDestinations") && exports && activeWorkspaceId) {
8445
8709
  const documentId = JSON.stringify([activeWorkspaceId, selectedFile]);
8446
8710
  return {
8447
8711
  showDestination: false,
@@ -8456,11 +8720,11 @@ function DocBlocksShell({
8456
8720
  return createBrowserSaveAsAdapter();
8457
8721
  }, [activeWorkspaceId, selectedFile]);
8458
8722
  const saveRenderedImageOutput = useMemo6(
8459
- () => hostSupports2("exportDestinations") && exportDestinationAdapter ? createImageSaveOutput(exportDestinationAdapter) : void 0,
8723
+ () => hostSupports3("exportDestinations") && exportDestinationAdapter ? createImageSaveOutput(exportDestinationAdapter) : void 0,
8460
8724
  [exportDestinationAdapter]
8461
8725
  );
8462
- const [selectedFolder, setSelectedFolder] = useState24(null);
8463
- const [folderEntries, setFolderEntries] = useState24([]);
8726
+ const [selectedFolder, setSelectedFolder] = useState25(null);
8727
+ const [folderEntries, setFolderEntries] = useState25([]);
8464
8728
  const visibleFolderEntries = useMemo6(
8465
8729
  () => filterVisibleFileEntries(folderEntries),
8466
8730
  [folderEntries]
@@ -8474,8 +8738,8 @@ function DocBlocksShell({
8474
8738
  } : null,
8475
8739
  [documentSnapshot.frozen, documentSnapshot.generation, documentSnapshot.targetKey]
8476
8740
  );
8477
- const [editorGeneration, setEditorGeneration] = useState24(documentSnapshot.generation);
8478
- useEffect30(() => {
8741
+ const [editorGeneration, setEditorGeneration] = useState25(documentSnapshot.generation);
8742
+ useEffect31(() => {
8479
8743
  const sync = () => setEditorGeneration(documentSession.getSnapshot().generation);
8480
8744
  const unsubscribe = documentSession.subscribe(sync);
8481
8745
  sync();
@@ -8484,7 +8748,7 @@ function DocBlocksShell({
8484
8748
  };
8485
8749
  }, [documentSession]);
8486
8750
  const editorGenerationSettled = editorGeneration === documentSnapshot.generation;
8487
- useEffect30(() => {
8751
+ useEffect31(() => {
8488
8752
  setOutsideInPdfWorker(pdfWorkerSrc2);
8489
8753
  }, [pdfWorkerSrc2]);
8490
8754
  const editorKey = String(editorGeneration);
@@ -8492,23 +8756,23 @@ function DocBlocksShell({
8492
8756
  void editorKey;
8493
8757
  return pickEmptyDocumentPrompt();
8494
8758
  }, [editorKey]);
8495
- const [explorerKey, setExplorerKey] = useState24(0);
8759
+ const [explorerKey, setExplorerKey] = useState25(0);
8496
8760
  const workspaceOutputsResult = workspaceOutputs.status.result;
8497
- useEffect30(() => {
8761
+ useEffect31(() => {
8498
8762
  if (!workspaceOutputsResult?.outputs.some((output) => output.created)) return;
8499
8763
  if (provider && getFileSystemProviderV211(provider)?.capabilities.watch) return;
8500
8764
  setExplorerKey((key) => key + 1);
8501
8765
  }, [provider, workspaceOutputsResult]);
8502
- const [fileExplorerSortMode, setFileExplorerSortMode] = useState24(loadFileExplorerSortMode);
8766
+ const [fileExplorerSortMode, setFileExplorerSortMode] = useState25(loadFileExplorerSortMode);
8503
8767
  const handleFileExplorerSortModeChange = useCallback19((mode) => {
8504
8768
  setFileExplorerSortMode(mode);
8505
8769
  saveFileExplorerSortMode(mode);
8506
8770
  }, []);
8507
- const [initialView, setInitialView] = useState24("wysiwyg");
8508
- const [initialSharedMode, setInitialSharedMode] = useState24(null);
8509
- const [showWelcomeGateway, setShowWelcomeGateway] = useState24(false);
8771
+ const [initialView, setInitialView] = useState25("wysiwyg");
8772
+ const [initialSharedMode, setInitialSharedMode] = useState25(null);
8773
+ const [showWelcomeGateway, setShowWelcomeGateway] = useState25(false);
8510
8774
  const welcomeScreenShown = showWelcomeGateway && !singlePane;
8511
- const welcomeCoveredRef = useRef20(null);
8775
+ const welcomeCoveredRef = useRef21(null);
8512
8776
  useInert(welcomeCoveredRef, welcomeScreenShown);
8513
8777
  const closeWelcomeGateway = useCallback19(() => {
8514
8778
  setShowWelcomeGateway((showing) => {
@@ -8516,11 +8780,11 @@ function DocBlocksShell({
8516
8780
  return false;
8517
8781
  });
8518
8782
  }, []);
8519
- const [aiPanel, setAiPanel] = useState24(null);
8520
- const navigationRequestRef = useRef20(0);
8783
+ const [aiPanel, setAiPanel] = useState25(null);
8784
+ const navigationRequestRef = useRef21(0);
8521
8785
  const workspaceAuthorityBarrier = useMemo6(() => new WorkspaceAuthorityBarrier(), []);
8522
- const preparedCloseRequestRef = useRef20(null);
8523
- const pendingDbkConflictsRef = useRef20(/* @__PURE__ */ new Map());
8786
+ const preparedCloseRequestRef = useRef21(null);
8787
+ const pendingDbkConflictsRef = useRef21(/* @__PURE__ */ new Map());
8524
8788
  const afterWorkspaceCommit = useCallback19(
8525
8789
  (workspaceId, path) => {
8526
8790
  gitScheduleRefresh();
@@ -8538,11 +8802,11 @@ function DocBlocksShell({
8538
8802
  outsideInRenderRef.current
8539
8803
  );
8540
8804
  }
8541
- const transient = getTransientWorkspace(workspaceId);
8805
+ const transient = getTransientWorkspace2(workspaceId);
8542
8806
  const baseTarget = createFileSystemDocumentTarget2(fsProvider, filePath);
8543
8807
  const originKind = transient?.descriptor.origin?.kind;
8544
8808
  const needsExternalResources = originKind === "loose-file" || originKind === "dbk";
8545
- if (!transient?.descriptor.origin || needsExternalResources && !hostSupports2("externalResources")) {
8809
+ if (!transient?.descriptor.origin || needsExternalResources && !hostSupports3("externalResources")) {
8546
8810
  return {
8547
8811
  key: baseTarget.key,
8548
8812
  async commit(request) {
@@ -8704,13 +8968,13 @@ function DocBlocksShell({
8704
8968
  },
8705
8969
  [afterWorkspaceCommit, gitScheduleRefresh]
8706
8970
  );
8707
- const mediaContainerRef = useRef20(null);
8708
- const [mediaProvider, setMediaProvider] = useState24(null);
8709
- const [mediaProviderScope, setMediaProviderScope] = useState24(null);
8971
+ const mediaContainerRef = useRef21(null);
8972
+ const [mediaProvider, setMediaProvider] = useState25(null);
8973
+ const [mediaProviderScope, setMediaProviderScope] = useState25(null);
8710
8974
  const mediaProviderCurrent = mediaProviderScope !== null && mediaProviderScope.provider === provider && mediaProviderScope.file === selectedFile && mediaProviderScope.outsideIn === selectedOutsideIn;
8711
- const [mediaEpoch, setMediaEpoch] = useState24(0);
8712
- const versionsContainerRef = useRef20(null);
8713
- const [versionsContainer, setVersionsContainer] = useState24(null);
8975
+ const [mediaEpoch, setMediaEpoch] = useState25(0);
8976
+ const versionsContainerRef = useRef21(null);
8977
+ const [versionsContainer, setVersionsContainer] = useState25(null);
8714
8978
  const pushHash = useCallback19((wsId, filePath) => {
8715
8979
  const hash = buildHash(wsId, filePath);
8716
8980
  if (window.location.hash !== hash) {
@@ -8721,7 +8985,7 @@ function DocBlocksShell({
8721
8985
  async (wsId, filePath, push, view, navigationRequestId, sharedMode = null) => {
8722
8986
  const requestId = navigationRequestId ?? ++navigationRequestRef.current;
8723
8987
  if (requestId !== navigationRequestRef.current) return null;
8724
- const transient = getTransientWorkspace(wsId);
8988
+ const transient = getTransientWorkspace2(wsId);
8725
8989
  let ws;
8726
8990
  let fsProvider = null;
8727
8991
  if (transient) {
@@ -8827,7 +9091,7 @@ function DocBlocksShell({
8827
9091
  if (opened) closeWelcomeGateway();
8828
9092
  return opened;
8829
9093
  } finally {
8830
- if (!opened && getTransientWorkspace(options.id)?.provider === options.provider) {
9094
+ if (!opened && getTransientWorkspace2(options.id)?.provider === options.provider) {
8831
9095
  await unregisterTransientWorkspace(options.id);
8832
9096
  }
8833
9097
  }
@@ -8928,28 +9192,28 @@ function DocBlocksShell({
8928
9192
  showBrowserStorageWarning
8929
9193
  ]
8930
9194
  );
8931
- const startupOpenFromIdsRef = useRef20(openFromIds);
9195
+ const startupOpenFromIdsRef = useRef21(openFromIds);
8932
9196
  startupOpenFromIdsRef.current = openFromIds;
8933
- const startupOpenSharedDocumentRef = useRef20(openSharedDocument);
9197
+ const startupOpenSharedDocumentRef = useRef21(openSharedDocument);
8934
9198
  startupOpenSharedDocumentRef.current = openSharedDocument;
8935
- const startupSeedWelcomeFileRef = useRef20(seedWelcomeFile);
9199
+ const startupSeedWelcomeFileRef = useRef21(seedWelcomeFile);
8936
9200
  startupSeedWelcomeFileRef.current = seedWelcomeFile;
8937
- const [focusAfterWelcome, setFocusAfterWelcome] = useState24(false);
9201
+ const [focusAfterWelcome, setFocusAfterWelcome] = useState25(false);
8938
9202
  const handleTourWelcome = useCallback19(() => {
8939
9203
  closeWelcomeGateway();
8940
9204
  setFocusAfterWelcome(true);
8941
9205
  }, [closeWelcomeGateway]);
8942
- useEffect30(() => {
9206
+ useEffect31(() => {
8943
9207
  if (!focusAfterWelcome || welcomeScreenShown) return;
8944
9208
  setFocusAfterWelcome(false);
8945
9209
  editorAreaRef.current?.querySelector('[contenteditable="true"]')?.focus({ preventScroll: true });
8946
9210
  }, [focusAfterWelcome, welcomeScreenShown]);
8947
- useEffect30(() => {
9211
+ useEffect31(() => {
8948
9212
  const requestId = ++navigationRequestRef.current;
8949
9213
  let cancelled = false;
8950
9214
  const isCurrent = () => !cancelled && requestId === navigationRequestRef.current;
8951
9215
  void (async () => {
8952
- const electron = hostSupports2("workspaceAuthority");
9216
+ const electron = hostSupports3("workspaceAuthority");
8953
9217
  let workspaceIdRemap = {};
8954
9218
  const defaultHostWorkspaceIds = /* @__PURE__ */ new Set();
8955
9219
  const isDefaultWorkspace = (workspaceId) => isAppDefaultWorkspace(workspaceId, electron ? defaultHostWorkspaceIds : null);
@@ -9156,7 +9420,7 @@ function DocBlocksShell({
9156
9420
  if (navigationRequestRef.current === requestId) navigationRequestRef.current += 1;
9157
9421
  };
9158
9422
  }, [pushHash, workspaceAuthorityBarrier]);
9159
- useEffect30(() => {
9423
+ useEffect31(() => {
9160
9424
  const onPopState = () => {
9161
9425
  const requestedHash = window.location.hash;
9162
9426
  const restoreCurrentHash = () => {
@@ -9198,7 +9462,7 @@ function DocBlocksShell({
9198
9462
  window.addEventListener("popstate", onPopState);
9199
9463
  return () => window.removeEventListener("popstate", onPopState);
9200
9464
  }, [activeWorkspaceId, openFromIds, openSharedDocument, selectedFile, showToast]);
9201
- useEffect30(() => {
9465
+ useEffect31(() => {
9202
9466
  if (!showBrowserStorageWarning || typeof navigator === "undefined") return;
9203
9467
  const storage = navigator.storage;
9204
9468
  if (!storage || typeof storage.persisted !== "function") return;
@@ -9211,7 +9475,7 @@ function DocBlocksShell({
9211
9475
  cancelled = true;
9212
9476
  };
9213
9477
  }, [showBrowserStorageWarning]);
9214
- useEffect30(() => {
9478
+ useEffect31(() => {
9215
9479
  if (hasDocBlocksHost() || typeof window === "undefined") return;
9216
9480
  const onBeforeInstallPrompt = (e) => {
9217
9481
  e.preventDefault();
@@ -9244,7 +9508,7 @@ function DocBlocksShell({
9244
9508
  } catch {
9245
9509
  }
9246
9510
  }, [installPromptEvent]);
9247
- useEffect30(() => {
9511
+ useEffect31(() => {
9248
9512
  const handler = (e) => {
9249
9513
  const target = e.target.closest?.("[data-view]");
9250
9514
  if (target) {
@@ -9260,12 +9524,18 @@ function DocBlocksShell({
9260
9524
  window.addEventListener("click", handler, true);
9261
9525
  return () => window.removeEventListener("click", handler, true);
9262
9526
  }, [activeWorkspaceId, selectedFile, closeWelcomeGateway]);
9527
+ const [dismissedConflictKey, setDismissedConflictKey] = useState25(null);
9528
+ const conflictTargetKey = documentSnapshot.conflict?.targetKey ?? null;
9529
+ useEffect31(() => {
9530
+ if (conflictTargetKey === null) setDismissedConflictKey(null);
9531
+ }, [conflictTargetKey]);
9263
9532
  const saveActiveDocument = useCallback19(() => {
9264
9533
  void (async () => {
9265
9534
  try {
9266
9535
  await documentSession.flush("manual");
9267
9536
  showToast("success", "Saved. You\u2019re all set.");
9268
9537
  } catch (error) {
9538
+ if (error instanceof DocumentSessionConflictError) setDismissedConflictKey(null);
9269
9539
  showToast(
9270
9540
  "error",
9271
9541
  isQuotaExceededError(error) ? "Could not save -- browser storage is full. Free up space or back up your work." : error instanceof Error ? error.message : "Could not save this document."
@@ -9273,30 +9543,30 @@ function DocBlocksShell({
9273
9543
  }
9274
9544
  })();
9275
9545
  }, [documentSession, showToast]);
9276
- useEffect30(() => {
9546
+ useEffect31(() => {
9277
9547
  return () => {
9278
9548
  if (saveToastTimerRef.current) clearTimeout(saveToastTimerRef.current);
9279
9549
  };
9280
9550
  }, []);
9281
- const [offlineReadyToast, setOfflineReadyToast] = useState24(false);
9282
- const offlineReadyAnnouncedRef = useRef20(false);
9283
- useEffect30(() => {
9551
+ const [offlineReadyToast, setOfflineReadyToast] = useState25(false);
9552
+ const offlineReadyAnnouncedRef = useRef21(false);
9553
+ useEffect31(() => {
9284
9554
  if (!offlineReady || offlineReadyAnnouncedRef.current) return;
9285
9555
  offlineReadyAnnouncedRef.current = true;
9286
9556
  setOfflineReadyToast(true);
9287
9557
  const timer = setTimeout(() => setOfflineReadyToast(false), 3e3);
9288
9558
  return () => clearTimeout(timer);
9289
9559
  }, [offlineReady]);
9290
- const [storageFull, setStorageFull] = useState24(false);
9291
- useEffect30(() => {
9560
+ const [storageFull, setStorageFull] = useState25(false);
9561
+ useEffect31(() => {
9292
9562
  if (documentSnapshot.error && isQuotaExceededError(documentSnapshot.error)) {
9293
9563
  setStorageFull(true);
9294
9564
  } else if (documentSnapshot.status === "saved") {
9295
9565
  setStorageFull(false);
9296
9566
  }
9297
9567
  }, [documentSnapshot.error, documentSnapshot.status]);
9298
- const autoPersistRequestedRef = useRef20(false);
9299
- useEffect30(() => {
9568
+ const autoPersistRequestedRef = useRef21(false);
9569
+ useEffect31(() => {
9300
9570
  if (!showBrowserStorageWarning || browserStoragePersistent) return;
9301
9571
  if (autoPersistRequestedRef.current) return;
9302
9572
  if (documentSnapshot.status !== "saved") return;
@@ -9330,12 +9600,18 @@ function DocBlocksShell({
9330
9600
  const parentDir = dirnameOf(selectedFile);
9331
9601
  const base = basenameOf(selectedFile);
9332
9602
  const baseNoExt = base.replace(/\.[^.]+$/, "");
9333
- const container = new FileSystemContentContainer2(provider, parentDir);
9603
+ const readBeside = looseFileMediaReader(provider.id);
9604
+ const container = createMediaContainer(provider, parentDir, readBeside);
9334
9605
  const vPrefix = parentDir ? `${parentDir}/${baseNoExt}_files` : `${baseNoExt}_files`;
9335
- const vContainer = new FileSystemContentContainer2(provider, vPrefix, {
9606
+ const vContainer = new FileSystemContentContainer3(provider, vPrefix, {
9336
9607
  documentMediaPrefix: `${baseNoExt}_files`
9337
9608
  });
9338
- const mp = createFileMediaProvider(container, base);
9609
+ const mp = createFileMediaProvider(container, base, {
9610
+ readDocumentRelative: createDocumentRelativeMediaReader(
9611
+ createMediaContainer(provider, "", readBeside),
9612
+ parentDir
9613
+ )
9614
+ });
9339
9615
  mediaContainerRef.current = container;
9340
9616
  versionsContainerRef.current = vContainer;
9341
9617
  setMediaProvider(mp);
@@ -9344,8 +9620,8 @@ function DocBlocksShell({
9344
9620
  mp.dispose();
9345
9621
  };
9346
9622
  }, [provider, selectedFile, selectedOutsideIn, mediaEpoch]);
9347
- const [mediaEditRenders, setMediaEditRenders] = useState24(null);
9348
- useEffect30(() => {
9623
+ const [mediaEditRenders, setMediaEditRenders] = useState25(null);
9624
+ useEffect31(() => {
9349
9625
  setMediaEditRenders(null);
9350
9626
  if (!mediaProvider) return;
9351
9627
  let manager = null;
@@ -9369,7 +9645,7 @@ function DocBlocksShell({
9369
9645
  selectedSourceFile ?? selectedFile,
9370
9646
  workspaceIndex.ensure
9371
9647
  );
9372
- useEffect30(() => {
9648
+ useEffect31(() => {
9373
9649
  const ref = versioningRef;
9374
9650
  if (!ref) return;
9375
9651
  const assign = (mgr2) => {
@@ -9393,10 +9669,10 @@ function DocBlocksShell({
9393
9669
  (output) => output.status === "written" && sameProviderPath(output.path, selectedFile)
9394
9670
  ) ? workspaceOutputsResult : null;
9395
9671
  }, [selectedFile, selectedManagedOutput, workspaceOutputsResult]);
9396
- useEffect30(() => {
9672
+ useEffect31(() => {
9397
9673
  if (!provider) return;
9398
9674
  const providerV2 = getFileSystemProviderV211(provider);
9399
- const lifecycle = maybeGetDocBlocksHost4()?.lifecycle;
9675
+ const lifecycle = maybeGetDocBlocksHost5()?.lifecycle;
9400
9676
  if (!providerV2 || !providerV2.capabilities.watch && !lifecycle?.onResume && !managedOutputRefreshToken)
9401
9677
  return;
9402
9678
  const watchedFile = selectedSourceFile ?? selectedFile;
@@ -9484,6 +9760,7 @@ function DocBlocksShell({
9484
9760
  if (!transitioned || requestId !== navigationRequestRef.current) return false;
9485
9761
  return true;
9486
9762
  } catch (error) {
9763
+ if (error instanceof DocumentSessionConflictError) setDismissedConflictKey(null);
9487
9764
  showToast(
9488
9765
  "error",
9489
9766
  error instanceof Error ? "DocBlocks could not save this document: " + error.message : "DocBlocks could not save this document."
@@ -9493,10 +9770,10 @@ function DocBlocksShell({
9493
9770
  },
9494
9771
  [documentSession, showToast]
9495
9772
  );
9496
- const [showConflictComparison, setShowConflictComparison] = useState24(false);
9773
+ const [showConflictComparison, setShowConflictComparison] = useState25(false);
9497
9774
  const readConflictFile = useCallback19(async () => {
9498
9775
  const path = selectedSourceFile ?? selectedFile;
9499
- if (!provider || !path || activeWorkspaceId && getTransientWorkspace(activeWorkspaceId)) {
9776
+ if (!provider || !path || activeWorkspaceId && getTransientWorkspace2(activeWorkspaceId)) {
9500
9777
  return null;
9501
9778
  }
9502
9779
  return readStableFileSnapshot(provider, path);
@@ -9540,7 +9817,7 @@ function DocBlocksShell({
9540
9817
  return false;
9541
9818
  }
9542
9819
  }, [documentSession]);
9543
- useEffect30(() => {
9820
+ useEffect31(() => {
9544
9821
  const needsWarning = ["dirty", "saving", "error", "conflict"].includes(documentSnapshot.status);
9545
9822
  if (!documentSnapshot.targetKey) return;
9546
9823
  const flushBestEffort = () => {
@@ -9566,9 +9843,9 @@ function DocBlocksShell({
9566
9843
  document.removeEventListener("visibilitychange", onVisibilityChange);
9567
9844
  };
9568
9845
  }, [documentSession, documentSnapshot.status, documentSnapshot.targetKey]);
9569
- useEffect30(() => {
9570
- const lifecycle = maybeGetDocBlocksHost4()?.lifecycle;
9571
- if (!hostSupports2("guardedClose") || !lifecycle) return;
9846
+ useEffect31(() => {
9847
+ const lifecycle = maybeGetDocBlocksHost5()?.lifecycle;
9848
+ if (!hostSupports3("guardedClose") || !lifecycle) return;
9572
9849
  const stopPrepare = lifecycle.onPrepareClose(async (request) => {
9573
9850
  preparedCloseRequestRef.current = request.requestId;
9574
9851
  try {
@@ -9598,7 +9875,7 @@ function DocBlocksShell({
9598
9875
  await touchWorkspace2(ws.id);
9599
9876
  if (requestId !== navigationRequestRef.current) return;
9600
9877
  let nextProvider = null;
9601
- const transient = getTransientWorkspace(ws.id);
9878
+ const transient = getTransientWorkspace2(ws.id);
9602
9879
  if (transient) {
9603
9880
  nextProvider = transient.provider;
9604
9881
  } else if (ws.type === "host-native") {
@@ -9699,11 +9976,11 @@ function DocBlocksShell({
9699
9976
  let adoptedNextProvider = nextProvider !== null;
9700
9977
  try {
9701
9978
  if (!nextProvider) {
9702
- const transient = getTransientWorkspace(workspace.id);
9979
+ const transient = getTransientWorkspace2(workspace.id);
9703
9980
  if (transient) {
9704
9981
  nextProvider = transient.provider;
9705
9982
  } else if (workspace.type === "host-native") {
9706
- nextProvider = hostSupports2("nativeWorkspaces") ? await createHostProviderFromWorkspace(workspace) : null;
9983
+ nextProvider = hostSupports3("nativeWorkspaces") ? await createHostProviderFromWorkspace(workspace) : null;
9707
9984
  ownsNextProvider = nextProvider !== null;
9708
9985
  } else if (workspace.type === "native") {
9709
9986
  nextProvider = await (await loadNativeFileSystem()).restoreNativeFolder(workspace.id);
@@ -9818,7 +10095,7 @@ function DocBlocksShell({
9818
10095
  if (!activeWorkspaceId || !provider || !selectedFile) {
9819
10096
  throw new Error("Select the temporary document before moving it.");
9820
10097
  }
9821
- const transient = getTransientWorkspace(activeWorkspaceId);
10098
+ const transient = getTransientWorkspace2(activeWorkspaceId);
9822
10099
  if (!transient || transient.provider !== provider) {
9823
10100
  throw new Error("This workspace is no longer temporary.");
9824
10101
  }
@@ -9891,7 +10168,7 @@ function DocBlocksShell({
9891
10168
  void touchWorkspace2(destination.id).catch(() => void 0);
9892
10169
  if (sourceTargetKey) pendingDbkConflictsRef.current.delete(sourceTargetKey);
9893
10170
  const origin = transient.descriptor.origin;
9894
- const externalApi = maybeGetDocBlocksHost4()?.external;
10171
+ const externalApi = maybeGetDocBlocksHost5()?.external;
9895
10172
  if (externalApi && origin && (origin.kind === "loose-file" || origin.kind === "dbk")) {
9896
10173
  try {
9897
10174
  await externalApi.revoke(origin.resourceId);
@@ -9930,7 +10207,7 @@ function DocBlocksShell({
9930
10207
  const handleOpenFolder = useCallback19(async () => {
9931
10208
  const requestId = ++navigationRequestRef.current;
9932
10209
  try {
9933
- if (hostSupports2("workspaceFolderPicker")) {
10210
+ if (hostSupports3("workspaceFolderPicker")) {
9934
10211
  const info = await getDocBlocksHost().workspaces.pickFolder?.();
9935
10212
  if (!info) return;
9936
10213
  if (requestId !== navigationRequestRef.current) return;
@@ -10148,7 +10425,7 @@ function DocBlocksShell({
10148
10425
  singlePane
10149
10426
  ]);
10150
10427
  const canFind = selectedFile !== null && mediaProvider !== null && selectedManagedOutput !== "catalog-html" && selectedImage === void 0;
10151
- const canFindRef = useRef20(canFind);
10428
+ const canFindRef = useRef21(canFind);
10152
10429
  canFindRef.current = canFind;
10153
10430
  const { ensure: ensureWorkspaceIndex } = workspaceIndex;
10154
10431
  const openQuickOpen = useCallback19(() => {
@@ -10224,8 +10501,8 @@ function DocBlocksShell({
10224
10501
  ]
10225
10502
  );
10226
10503
  useShellShortcuts(shortcutHandlers, layoutMode);
10227
- useEffect30(
10228
- () => maybeGetDocBlocksHost4()?.lifecycle?.onBack?.(() => {
10504
+ useEffect31(
10505
+ () => maybeGetDocBlocksHost5()?.lifecycle?.onBack?.(() => {
10229
10506
  if (dismissTopmostDialog()) return true;
10230
10507
  const escape = new KeyboardEvent("keydown", {
10231
10508
  key: "Escape",
@@ -10246,8 +10523,8 @@ function DocBlocksShell({
10246
10523
  }),
10247
10524
  [singlePane, mobileShowEditor]
10248
10525
  );
10249
- const actionNewHandledRef = useRef20(false);
10250
- useEffect30(() => {
10526
+ const actionNewHandledRef = useRef21(false);
10527
+ useEffect31(() => {
10251
10528
  if (!provider || actionNewHandledRef.current) return;
10252
10529
  if (typeof window === "undefined") return;
10253
10530
  const params = new URLSearchParams(window.location.search);
@@ -10263,8 +10540,8 @@ function DocBlocksShell({
10263
10540
  void handleNewFile();
10264
10541
  }, [provider, handleNewFile]);
10265
10542
  const handleRevealWorkspace = useCallback19(async () => {
10266
- const shell = maybeGetDocBlocksHost4()?.shell;
10267
- if (!hostSupports2("revealInFileManager") || !shell?.revealInFolder || !activeWorkspaceId) {
10543
+ const shell = maybeGetDocBlocksHost5()?.shell;
10544
+ if (!hostSupports3("revealInFileManager") || !shell?.revealInFolder || !activeWorkspaceId) {
10268
10545
  return;
10269
10546
  }
10270
10547
  const ws = await getWorkspace(activeWorkspaceId);
@@ -10273,8 +10550,8 @@ function DocBlocksShell({
10273
10550
  }
10274
10551
  }, [activeWorkspaceId]);
10275
10552
  const handleOpenWorkspaceFolder = useCallback19(() => {
10276
- const shell = maybeGetDocBlocksHost4()?.shell;
10277
- if (!hostSupports2("openWorkspaceFolder") || !shell?.openWorkspaceFolder || !nativeWorkspaceId) {
10553
+ const shell = maybeGetDocBlocksHost5()?.shell;
10554
+ if (!hostSupports3("openWorkspaceFolder") || !shell?.openWorkspaceFolder || !nativeWorkspaceId) {
10278
10555
  return;
10279
10556
  }
10280
10557
  void shell.openWorkspaceFolder(nativeWorkspaceId).catch((error) => {
@@ -10284,9 +10561,9 @@ function DocBlocksShell({
10284
10561
  );
10285
10562
  });
10286
10563
  }, [nativeWorkspaceId, showToast]);
10287
- useEffect30(() => {
10288
- const host = maybeGetDocBlocksHost4();
10289
- if (!hostSupports2("menuCommands") || !host?.onMenuCommand) return;
10564
+ useEffect31(() => {
10565
+ const host = maybeGetDocBlocksHost5();
10566
+ if (!hostSupports3("menuCommands") || !host?.onMenuCommand) return;
10290
10567
  return host.onMenuCommand((cmd) => {
10291
10568
  switch (cmd) {
10292
10569
  case "file:new":
@@ -10342,7 +10619,7 @@ function DocBlocksShell({
10342
10619
  break;
10343
10620
  case "help:about":
10344
10621
  void (async () => {
10345
- const version = await host.updater?.getVersion() ?? getHostEnvironment2()?.appVersion ?? "unknown";
10622
+ const version = await host.updater?.getVersion() ?? getHostEnvironment3()?.appVersion ?? "unknown";
10346
10623
  await acknowledge({ title: "About DocBlocks", message: `DocBlocks ${version}` });
10347
10624
  })();
10348
10625
  break;
@@ -10435,7 +10712,7 @@ function DocBlocksShell({
10435
10712
  defaultNewFileFormat
10436
10713
  ]
10437
10714
  );
10438
- const wikiNavigationRef = useRef20(handleSelect);
10715
+ const wikiNavigationRef = useRef21(handleSelect);
10439
10716
  wikiNavigationRef.current = handleSelect;
10440
10717
  const wikiLinks = useMemo6(() => {
10441
10718
  if (!provider || !selectedFile || !activeWorkspaceId) return null;
@@ -10580,7 +10857,7 @@ function DocBlocksShell({
10580
10857
  const nativeActions = createNativeFileActions(
10581
10858
  entry,
10582
10859
  nativeWorkspaceId,
10583
- maybeGetDocBlocksHost4()
10860
+ maybeGetDocBlocksHost5()
10584
10861
  );
10585
10862
  return [...nativeActions, ...outsideInActionsForEntry(entry)];
10586
10863
  },
@@ -10819,13 +11096,13 @@ function DocBlocksShell({
10819
11096
  if (activeWorkspaceId === workspace.id && provider) {
10820
11097
  return { kind: "ready", workspace, provider, owned: false };
10821
11098
  }
10822
- const transient = getTransientWorkspace(workspace.id);
11099
+ const transient = getTransientWorkspace2(workspace.id);
10823
11100
  if (transient) {
10824
11101
  return { kind: "ready", workspace, provider: transient.provider, owned: false };
10825
11102
  }
10826
11103
  let pinnedProvider = null;
10827
11104
  if (workspace.type === "host-native") {
10828
- pinnedProvider = hostSupports2("nativeWorkspaces") ? await createHostProviderFromWorkspace(workspace) : null;
11105
+ pinnedProvider = hostSupports3("nativeWorkspaces") ? await createHostProviderFromWorkspace(workspace) : null;
10829
11106
  } else if (workspace.type === "native") {
10830
11107
  pinnedProvider = await (await loadNativeFileSystem()).restoreNativeFolder(workspace.id);
10831
11108
  } else {
@@ -11010,8 +11287,8 @@ function DocBlocksShell({
11010
11287
  showToast
11011
11288
  ]
11012
11289
  );
11013
- const restoreInputRef = useRef20(null);
11014
- const restoreInProgress = useRef20(false);
11290
+ const restoreInputRef = useRef21(null);
11291
+ const restoreInProgress = useRef21(false);
11015
11292
  const handleRestoreBackup = useCallback19(
11016
11293
  async (file) => {
11017
11294
  if (restoreInProgress.current) {
@@ -11041,7 +11318,7 @@ function DocBlocksShell({
11041
11318
  );
11042
11319
  const importOrRestore = useCallback19(
11043
11320
  async (files) => {
11044
- const backups = hostSupports2("nativeWorkspaces") ? [] : files.filter((file) => /\.zip$/i.test(file.name));
11321
+ const backups = hostSupports3("nativeWorkspaces") ? [] : files.filter((file) => /\.zip$/i.test(file.name));
11045
11322
  const documents = files.filter((file) => !backups.includes(file));
11046
11323
  const result = provider ? await importDroppedFiles(documents, provider) : null;
11047
11324
  for (const file of backups) await handleRestoreBackup(file);
@@ -11187,9 +11464,9 @@ function DocBlocksShell({
11187
11464
  },
11188
11465
  [adoptTransientWorkspace]
11189
11466
  );
11190
- useEffect30(() => {
11191
- const host = maybeGetDocBlocksHost4();
11192
- if (!hostSupports2("openRequests") || !host) return;
11467
+ useEffect31(() => {
11468
+ const host = maybeGetDocBlocksHost5();
11469
+ if (!hostSupports3("openRequests") || !host) return;
11193
11470
  return host.onOpenRequest((req) => {
11194
11471
  const requestId = ++navigationRequestRef.current;
11195
11472
  void (req.kind === "workspace-file" ? workspaceAuthorityBarrier.wait().then(() => {
@@ -11254,8 +11531,8 @@ function DocBlocksShell({
11254
11531
  },
11255
11532
  [adoptTransientWorkspace]
11256
11533
  );
11257
- useEffect30(() => {
11258
- if (hostSupports2("openRequests") || typeof window === "undefined") return;
11534
+ useEffect31(() => {
11535
+ if (hostSupports3("openRequests") || typeof window === "undefined") return;
11259
11536
  const launchQueue = window.launchQueue;
11260
11537
  if (!launchQueue) return;
11261
11538
  launchQueue.setConsumer((params) => {
@@ -11302,7 +11579,7 @@ function DocBlocksShell({
11302
11579
  import("@bendyline/squisq/storage"),
11303
11580
  import("@bendyline/squisq-formats/container")
11304
11581
  ]);
11305
- const electron = hostSupports2("nativeWorkspaces");
11582
+ const electron = hostSupports3("nativeWorkspaces");
11306
11583
  const all = await listWorkspaces2();
11307
11584
  const candidates = all.filter(
11308
11585
  (w) => electron ? w.type === "host-native" || w.type === "transient" : w.type !== "host-native"
@@ -11318,7 +11595,7 @@ function DocBlocksShell({
11318
11595
  let p = null;
11319
11596
  let ownsProvider = false;
11320
11597
  try {
11321
- const transient = getTransientWorkspace(ws.id);
11598
+ const transient = getTransientWorkspace2(ws.id);
11322
11599
  if (transient) {
11323
11600
  p = transient.provider;
11324
11601
  } else if (ws.type === "host-native") {
@@ -11444,7 +11721,7 @@ function DocBlocksShell({
11444
11721
  }
11445
11722
  } else if (ws?.type === "transient") {
11446
11723
  const origin = ws.origin;
11447
- const externalApi = maybeGetDocBlocksHost4()?.external;
11724
+ const externalApi = maybeGetDocBlocksHost5()?.external;
11448
11725
  if (externalApi && origin && (origin.kind === "loose-file" || origin.kind === "dbk")) {
11449
11726
  try {
11450
11727
  await externalApi.revoke(origin.resourceId);
@@ -11468,7 +11745,7 @@ function DocBlocksShell({
11468
11745
  return;
11469
11746
  }
11470
11747
  if (requestId !== navigationRequestRef.current) return;
11471
- const electron = hostSupports2("nativeWorkspaces");
11748
+ const electron = hostSupports3("nativeWorkspaces");
11472
11749
  const remaining = (await listWorkspaces2()).filter(
11473
11750
  (w) => electron ? w.type === "host-native" : w.type !== "host-native"
11474
11751
  );
@@ -11511,7 +11788,7 @@ function DocBlocksShell({
11511
11788
  transitionAwayFromDocument
11512
11789
  ]
11513
11790
  );
11514
- return /* @__PURE__ */ jsx19(
11791
+ return /* @__PURE__ */ jsx21(
11515
11792
  "div",
11516
11793
  {
11517
11794
  ref: shellRef,
@@ -11520,10 +11797,10 @@ function DocBlocksShell({
11520
11797
  "data-accent": accentColor,
11521
11798
  "data-interface-font": interfaceFont === "fixed" ? "fixed" : void 0,
11522
11799
  "data-document-status": documentSnapshot.status,
11523
- children: /* @__PURE__ */ jsxs17(GitContext.Provider, { value: git, children: [
11800
+ children: /* @__PURE__ */ jsxs19(GitContext.Provider, { value: git, children: [
11524
11801
  promptDialog,
11525
11802
  confirmDialog,
11526
- quickOpenOpen && activeWorkspaceId && /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx19(
11803
+ quickOpenOpen && activeWorkspaceId && /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx21(
11527
11804
  QuickOpenDialog,
11528
11805
  {
11529
11806
  index: workspaceIndex.index,
@@ -11537,8 +11814,8 @@ function DocBlocksShell({
11537
11814
  onClose: () => setQuickOpenOpen(false)
11538
11815
  }
11539
11816
  ) }),
11540
- shortcutsOpen && /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx19(KeyboardShortcutsDialog, { onClose: () => setShortcutsOpen(false) }) }),
11541
- newDocumentDialogOpen && /* @__PURE__ */ jsx19(
11817
+ shortcutsOpen && /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx21(KeyboardShortcutsDialog, { onClose: () => setShortcutsOpen(false) }) }),
11818
+ newDocumentDialogOpen && /* @__PURE__ */ jsx21(
11542
11819
  NewDocumentDialog,
11543
11820
  {
11544
11821
  initialFormat: defaultNewFileFormat,
@@ -11548,8 +11825,8 @@ function DocBlocksShell({
11548
11825
  }
11549
11826
  }
11550
11827
  ),
11551
- workspaceStartupError && /* @__PURE__ */ jsx19("div", { className: "db-save-toast db-save-toast--error", role: "alert", "aria-live": "assertive", children: workspaceStartupError }),
11552
- saveToast && /* @__PURE__ */ jsx19(
11828
+ workspaceStartupError && /* @__PURE__ */ jsx21("div", { className: "db-save-toast db-save-toast--error", role: "alert", "aria-live": "assertive", children: workspaceStartupError }),
11829
+ saveToast && /* @__PURE__ */ jsx21(
11553
11830
  "div",
11554
11831
  {
11555
11832
  className: "db-save-toast db-save-toast--" + saveToast.kind,
@@ -11558,29 +11835,38 @@ function DocBlocksShell({
11558
11835
  children: saveToast.message
11559
11836
  }
11560
11837
  ),
11561
- offlineReadyToast && !saveToast && /* @__PURE__ */ jsx19("div", { className: "db-save-toast db-save-toast--success", role: "status", "aria-live": "polite", children: "DocBlocks is ready to work offline." }),
11562
- documentSnapshot.conflict && /* @__PURE__ */ jsxs17("div", { className: "db-document-conflict", role: "alert", children: [
11563
- /* @__PURE__ */ jsx19("span", { children: documentSnapshot.conflict.recoveredDraft ? "A recovery draft from a previous session differs from the saved file. The saved file may be newer. Choose which version to use." : "This document changed outside DocBlocks. Your unsaved version is still intact." }),
11564
- /* @__PURE__ */ jsx19("div", { className: "db-document-conflict-actions", children: /* @__PURE__ */ jsx19("button", { type: "button", onClick: () => setShowConflictComparison(true), children: "Compare versions" }) })
11565
- ] }),
11566
- documentSnapshot.conflict && showConflictComparison && /* @__PURE__ */ jsx19(Suspense2, { fallback: /* @__PURE__ */ jsx19("div", { role: "status", children: "Loading version comparison\u2026" }), children: /* @__PURE__ */ jsx19(
11838
+ offlineReadyToast && !saveToast && /* @__PURE__ */ jsx21("div", { className: "db-save-toast db-save-toast--success", role: "status", "aria-live": "polite", children: "DocBlocks is ready to work offline." }),
11839
+ documentSnapshot.conflict && documentSnapshot.conflict.targetKey !== dismissedConflictKey && /* @__PURE__ */ jsx21(
11840
+ DocumentConflictBanner,
11841
+ {
11842
+ conflict: documentSnapshot.conflict,
11843
+ readSavedFile: readConflictFile,
11844
+ onCompare: () => setShowConflictComparison(true),
11845
+ onDismiss: () => setDismissedConflictKey(conflictTargetKey)
11846
+ }
11847
+ ),
11848
+ documentSnapshot.conflict && showConflictComparison && /* @__PURE__ */ jsx21(Suspense2, { fallback: /* @__PURE__ */ jsx21("div", { role: "status", children: "Loading version comparison\u2026" }), children: /* @__PURE__ */ jsx21(
11567
11849
  DocumentConflictDialog,
11568
11850
  {
11569
11851
  conflict: documentSnapshot.conflict,
11852
+ fileName: selectedSourceFile ?? selectedFile ?? "",
11853
+ theme: resolvedTheme,
11854
+ defaultThemeId: workspaceDefaultThemeId,
11855
+ mediaProvider: mediaProviderCurrent ? mediaProvider : null,
11570
11856
  readSavedFile: readConflictFile,
11571
11857
  onUseLocal: handleKeepLocalDocument,
11572
11858
  onUseSaved: handleUseExternalDocument,
11573
11859
  onClose: () => setShowConflictComparison(false)
11574
11860
  }
11575
11861
  ) }),
11576
- storageFull && !documentSnapshot.conflict && /* @__PURE__ */ jsxs17("div", { className: "db-storage-full-banner", role: "alert", children: [
11577
- /* @__PURE__ */ jsx19("span", { children: "Browser storage is full -- changes can\u2019t be saved. Free up space or back up your work now." }),
11578
- /* @__PURE__ */ jsxs17("div", { className: "db-storage-full-banner-actions", children: [
11579
- /* @__PURE__ */ jsx19("button", { type: "button", onClick: () => void handleDownloadAllWorkspaces(), children: "Back up all workspaces" }),
11580
- /* @__PURE__ */ jsx19("button", { type: "button", onClick: () => setStorageFull(false), children: "Dismiss" })
11862
+ storageFull && !documentSnapshot.conflict && /* @__PURE__ */ jsxs19("div", { className: "db-storage-full-banner", role: "alert", children: [
11863
+ /* @__PURE__ */ jsx21("span", { children: "Browser storage is full -- changes can\u2019t be saved. Free up space or back up your work now." }),
11864
+ /* @__PURE__ */ jsxs19("div", { className: "db-storage-full-banner-actions", children: [
11865
+ /* @__PURE__ */ jsx21("button", { type: "button", onClick: () => void handleDownloadAllWorkspaces(), children: "Back up all workspaces" }),
11866
+ /* @__PURE__ */ jsx21("button", { type: "button", onClick: () => setStorageFull(false), children: "Dismiss" })
11581
11867
  ] })
11582
11868
  ] }),
11583
- workspaceSettingsOpen && activeWorkspaceDescriptor && /* @__PURE__ */ jsx19(
11869
+ workspaceSettingsOpen && activeWorkspaceDescriptor && /* @__PURE__ */ jsx21(
11584
11870
  WorkspaceSettingsDialog,
11585
11871
  {
11586
11872
  workspace: activeWorkspaceDescriptor,
@@ -11593,8 +11879,8 @@ function DocBlocksShell({
11593
11879
  onClose: () => setWorkspaceSettingsOpen(false)
11594
11880
  }
11595
11881
  ),
11596
- /* @__PURE__ */ jsxs17("div", { className: "db-shell-panes", ref: panesRef, children: [
11597
- /* @__PURE__ */ jsxs17(
11882
+ /* @__PURE__ */ jsxs19("div", { className: "db-shell-panes", ref: panesRef, children: [
11883
+ /* @__PURE__ */ jsxs19(
11598
11884
  "aside",
11599
11885
  {
11600
11886
  ref: sidebarRef,
@@ -11602,8 +11888,8 @@ function DocBlocksShell({
11602
11888
  "aria-label": "Workspace and files",
11603
11889
  style: singlePane ? void 0 : { width: `${sidebarWidth}px` },
11604
11890
  children: [
11605
- /* @__PURE__ */ jsxs17("div", { className: "db-shell-sidebar-header", children: [
11606
- /* @__PURE__ */ jsx19(
11891
+ /* @__PURE__ */ jsxs19("div", { className: "db-shell-sidebar-header", children: [
11892
+ /* @__PURE__ */ jsx21(
11607
11893
  AppMenu,
11608
11894
  {
11609
11895
  logoUrl,
@@ -11625,7 +11911,7 @@ function DocBlocksShell({
11625
11911
  onVersioningPreferenceChange: handleVersioningPreferenceChange,
11626
11912
  onOpenWorkspaceSettings: activeWorkspaceDescriptor ? handleOpenWorkspaceSettings : void 0,
11627
11913
  onDownloadAllWorkspaces: handleDownloadAllWorkspaces,
11628
- onRestoreBackup: hostSupports2("nativeWorkspaces") ? void 0 : () => restoreInputRef.current?.click(),
11914
+ onRestoreBackup: hostSupports3("nativeWorkspaces") ? void 0 : () => restoreInputRef.current?.click(),
11629
11915
  onShowKeyboardShortcuts: singlePane ? void 0 : openKeyboardShortcuts,
11630
11916
  onKeepBrowserData: showBrowserStorageWarning && !browserStoragePersistent ? handleKeepBrowserData : void 0,
11631
11917
  onInstallApp: installPromptEvent ? handleInstallApp : void 0,
@@ -11636,10 +11922,11 @@ function DocBlocksShell({
11636
11922
  ai,
11637
11923
  speech,
11638
11924
  tray: trayMenu,
11639
- settingsRequest
11925
+ settingsRequest: settingsRequest.count,
11926
+ settingsRequestSection: settingsRequest.section
11640
11927
  }
11641
11928
  ),
11642
- /* @__PURE__ */ jsx19(
11929
+ /* @__PURE__ */ jsx21(
11643
11930
  "input",
11644
11931
  {
11645
11932
  ref: restoreInputRef,
@@ -11654,7 +11941,7 @@ function DocBlocksShell({
11654
11941
  }
11655
11942
  }
11656
11943
  ),
11657
- /* @__PURE__ */ jsx19(
11944
+ /* @__PURE__ */ jsx21(
11658
11945
  WorkspacePicker,
11659
11946
  {
11660
11947
  activeWorkspaceId,
@@ -11666,7 +11953,7 @@ function DocBlocksShell({
11666
11953
  onRemoveWorkspace: (workspace) => void handleRemoveWorkspace(workspace.id)
11667
11954
  }
11668
11955
  ),
11669
- /* @__PURE__ */ jsx19(
11956
+ /* @__PURE__ */ jsx21(
11670
11957
  WorkspaceSettingsButton,
11671
11958
  {
11672
11959
  onSettings: handleOpenWorkspaceSettings,
@@ -11677,26 +11964,26 @@ function DocBlocksShell({
11677
11964
  }
11678
11965
  }
11679
11966
  ),
11680
- canRestoreSplitView && /* @__PURE__ */ jsx19(
11967
+ canRestoreSplitView && /* @__PURE__ */ jsx21(
11681
11968
  "button",
11682
11969
  {
11683
11970
  className: "db-restore-split",
11684
11971
  onClick: () => updateSidebarPreference("pinned"),
11685
11972
  "aria-label": "Restore split view",
11686
11973
  title: "Restore split view",
11687
- children: /* @__PURE__ */ jsx19(SplitViewIcon, {})
11974
+ children: /* @__PURE__ */ jsx21(SplitViewIcon, {})
11688
11975
  }
11689
11976
  ),
11690
- /* @__PURE__ */ jsx19("span", { className: "db-window-drag-grip", "aria-hidden": true })
11977
+ /* @__PURE__ */ jsx21("span", { className: "db-window-drag-grip", "aria-hidden": true })
11691
11978
  ] }),
11692
- git.available && /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx19(
11979
+ git.available && /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx21(
11693
11980
  GitUI,
11694
11981
  {
11695
11982
  onOpenFile: (path) => void handleSelect(path, "file"),
11696
11983
  onWorkspaceCloned: handleWorkspaceCloned
11697
11984
  }
11698
11985
  ) }),
11699
- /* @__PURE__ */ jsx19(
11986
+ /* @__PURE__ */ jsx21(
11700
11987
  FileExplorer,
11701
11988
  {
11702
11989
  loading: workspaceStarting,
@@ -11720,7 +12007,7 @@ function DocBlocksShell({
11720
12007
  onPinnedDocumentDelete: handlePinnedDocumentDelete,
11721
12008
  onTogglePin: handleTogglePin,
11722
12009
  onSelect: handleSelect,
11723
- onOpenWorkspaceFolder: hostSupports2("openWorkspaceFolder") && nativeWorkspaceId ? handleOpenWorkspaceFolder : void 0,
12010
+ onOpenWorkspaceFolder: hostSupports3("openWorkspaceFolder") && nativeWorkspaceId ? handleOpenWorkspaceFolder : void 0,
11724
12011
  actionsForEntry,
11725
12012
  onTreeMutation: handleTreeMutation,
11726
12013
  onTreeChange: handleTreeChange,
@@ -11731,7 +12018,7 @@ function DocBlocksShell({
11731
12018
  },
11732
12019
  explorerKey
11733
12020
  ),
11734
- searchMounted && /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx19(
12021
+ searchMounted && /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx21(
11735
12022
  WorkspaceSearchPanel,
11736
12023
  {
11737
12024
  index: workspaceIndex.index,
@@ -11742,17 +12029,17 @@ function DocBlocksShell({
11742
12029
  onShowFiles: () => setSidebarView("files")
11743
12030
  }
11744
12031
  ) }),
11745
- singlePane && showWelcomeGateway && /* @__PURE__ */ jsxs17("section", { className: "db-mobile-first-run", "aria-labelledby": "db-mobile-first-run-title", children: [
11746
- /* @__PURE__ */ jsx19("p", { className: "db-mobile-first-run-eyebrow", children: "Local-first Markdown editor" }),
11747
- /* @__PURE__ */ jsx19("h1", { id: "db-mobile-first-run-title", children: "Welcome to DocBlocks" }),
11748
- /* @__PURE__ */ jsxs17("p", { children: [
12032
+ singlePane && showWelcomeGateway && /* @__PURE__ */ jsxs19("section", { className: "db-mobile-first-run", "aria-labelledby": "db-mobile-first-run-title", children: [
12033
+ /* @__PURE__ */ jsx21("p", { className: "db-mobile-first-run-eyebrow", children: "Local-first Markdown editor" }),
12034
+ /* @__PURE__ */ jsx21("h1", { id: "db-mobile-first-run-title", children: "Welcome to DocBlocks" }),
12035
+ /* @__PURE__ */ jsxs19("p", { children: [
11749
12036
  WELCOME_SUMMARY,
11750
12037
  " ",
11751
12038
  WELCOME_PRIVACY_NOTE
11752
12039
  ] }),
11753
- /* @__PURE__ */ jsxs17("div", { className: "db-mobile-first-run-actions", children: [
11754
- /* @__PURE__ */ jsx19("button", { type: "button", onClick: () => void handleNewFile(), children: "Create a document" }),
11755
- /* @__PURE__ */ jsx19(
12040
+ /* @__PURE__ */ jsxs19("div", { className: "db-mobile-first-run-actions", children: [
12041
+ /* @__PURE__ */ jsx21("button", { type: "button", onClick: () => void handleNewFile(), children: "Create a document" }),
12042
+ /* @__PURE__ */ jsx21(
11756
12043
  "button",
11757
12044
  {
11758
12045
  type: "button",
@@ -11766,14 +12053,14 @@ function DocBlocksShell({
11766
12053
  )
11767
12054
  ] })
11768
12055
  ] }),
11769
- git.available && git.pendingGrant && /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx19(GitGrantNotice, {}) }),
11770
- /* @__PURE__ */ jsxs17("div", { className: "db-shell-sidebar-footer", children: [
11771
- /* @__PURE__ */ jsx19("a", { href: "https://docblocks.com/docs/", target: "_blank", rel: "noopener noreferrer", children: "Docs" }),
11772
- /* @__PURE__ */ jsx19("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
11773
- /* @__PURE__ */ jsx19("a", { href: "https://docblocks.com/terms/", target: "_blank", rel: "noopener noreferrer", children: "Terms" }),
11774
- /* @__PURE__ */ jsx19("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
11775
- /* @__PURE__ */ jsx19("a", { href: issueReportUrl, target: "_blank", rel: "noopener noreferrer", children: "Report issue" }),
11776
- showBrowserStorageWarning && /* @__PURE__ */ jsx19(Fragment11, { children: /* @__PURE__ */ jsxs17(
12056
+ git.available && git.pendingGrant && /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx21(GitGrantNotice, {}) }),
12057
+ /* @__PURE__ */ jsxs19("div", { className: "db-shell-sidebar-footer", children: [
12058
+ /* @__PURE__ */ jsx21("a", { href: "https://docblocks.com/docs/", target: "_blank", rel: "noopener noreferrer", children: "Docs" }),
12059
+ /* @__PURE__ */ jsx21("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
12060
+ /* @__PURE__ */ jsx21("a", { href: "https://docblocks.com/terms/", target: "_blank", rel: "noopener noreferrer", children: "Terms" }),
12061
+ /* @__PURE__ */ jsx21("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
12062
+ /* @__PURE__ */ jsx21("a", { href: issueReportUrl, target: "_blank", rel: "noopener noreferrer", children: "Report issue" }),
12063
+ showBrowserStorageWarning && /* @__PURE__ */ jsx21(Fragment12, { children: /* @__PURE__ */ jsxs19(
11777
12064
  "button",
11778
12065
  {
11779
12066
  type: "button",
@@ -11782,20 +12069,20 @@ function DocBlocksShell({
11782
12069
  "aria-label": "Back up all workspaces",
11783
12070
  title: "Browsers can clear site data. Download a backup of every workspace.",
11784
12071
  children: [
11785
- /* @__PURE__ */ jsx19(BackupIcon, {}),
12072
+ /* @__PURE__ */ jsx21(BackupIcon, {}),
11786
12073
  "Back up"
11787
12074
  ]
11788
12075
  }
11789
12076
  ) })
11790
12077
  ] }),
11791
- /* @__PURE__ */ jsxs17("div", { className: "db-sidebar-collapse-preview", "aria-hidden": "true", children: [
11792
- /* @__PURE__ */ jsx19("span", { className: "db-sidebar-collapse-preview-icon", children: /* @__PURE__ */ jsx19(CollapseSidebarGlyph, {}) }),
11793
- /* @__PURE__ */ jsx19("span", { className: "db-sidebar-collapse-preview-label", children: "Release to hide files" })
12078
+ /* @__PURE__ */ jsxs19("div", { className: "db-sidebar-collapse-preview", "aria-hidden": "true", children: [
12079
+ /* @__PURE__ */ jsx21("span", { className: "db-sidebar-collapse-preview-icon", children: /* @__PURE__ */ jsx21(CollapseSidebarGlyph, {}) }),
12080
+ /* @__PURE__ */ jsx21("span", { className: "db-sidebar-collapse-preview-label", children: "Release to hide files" })
11794
12081
  ] })
11795
12082
  ]
11796
12083
  }
11797
12084
  ),
11798
- !singlePane && /* @__PURE__ */ jsx19(
12085
+ !singlePane && /* @__PURE__ */ jsx21(
11799
12086
  "div",
11800
12087
  {
11801
12088
  className: "db-shell-sidebar-resizer",
@@ -11805,7 +12092,7 @@ function DocBlocksShell({
11805
12092
  onPointerDown: handleResizerPointerDown
11806
12093
  }
11807
12094
  ),
11808
- singlePane && /* @__PURE__ */ jsx19(
12095
+ singlePane && /* @__PURE__ */ jsx21(
11809
12096
  "div",
11810
12097
  {
11811
12098
  className: "db-shell-scrim",
@@ -11813,7 +12100,7 @@ function DocBlocksShell({
11813
12100
  onPointerDown: () => setMobileShowEditor(true)
11814
12101
  }
11815
12102
  ),
11816
- /* @__PURE__ */ jsxs17(
12103
+ /* @__PURE__ */ jsxs19(
11817
12104
  "main",
11818
12105
  {
11819
12106
  ref: editorAreaRef,
@@ -11824,8 +12111,8 @@ function DocBlocksShell({
11824
12111
  editorDropActive ? "db-shell-editor-area--drop-active" : ""
11825
12112
  ].filter(Boolean).join(" "),
11826
12113
  children: [
11827
- /* @__PURE__ */ jsxs17("div", { ref: welcomeCoveredRef, className: "db-shell-editor-content", children: [
11828
- selectedFile && mediaProvider ? /* @__PURE__ */ jsx19(Fragment11, { children: selectedManagedOutput === "catalog-html" ? /* @__PURE__ */ jsx19(
12114
+ /* @__PURE__ */ jsxs19("div", { ref: welcomeCoveredRef, className: "db-shell-editor-content", children: [
12115
+ selectedFile && mediaProvider ? /* @__PURE__ */ jsx21(Fragment12, { children: selectedManagedOutput === "catalog-html" ? /* @__PURE__ */ jsx21(
11829
12116
  GeneratedCatalogPage,
11830
12117
  {
11831
12118
  html: editorContent,
@@ -11833,17 +12120,17 @@ function DocBlocksShell({
11833
12120
  onOpenSettings: activeWorkspaceDescriptor ? handleOpenWorkspaceSettings : void 0,
11834
12121
  onBack: singlePane ? openDrawer : void 0
11835
12122
  }
11836
- ) : /* @__PURE__ */ jsx19(
12123
+ ) : /* @__PURE__ */ jsx21(
11837
12124
  GeneratedFileFrame,
11838
12125
  {
11839
12126
  kind: selectedManagedOutput,
11840
12127
  onOpenSettings: activeWorkspaceDescriptor ? handleOpenWorkspaceSettings : void 0,
11841
12128
  onBack: singlePane ? openDrawer : void 0,
11842
- children: /* @__PURE__ */ jsx19(
12129
+ children: /* @__PURE__ */ jsx21(
11843
12130
  Suspense2,
11844
12131
  {
11845
- fallback: /* @__PURE__ */ jsx19("div", { className: "db-shell-empty", role: "status", children: "Loading your document\u2026" }),
11846
- children: editorGenerationSettled && mediaProviderCurrent && /* @__PURE__ */ jsx19(EditorErrorBoundary, { resetKey: `${selectedFile}-${editorKey}`, children: /* @__PURE__ */ jsx19(
12132
+ fallback: /* @__PURE__ */ jsx21("div", { className: "db-shell-empty", role: "status", children: "Loading your document\u2026" }),
12133
+ children: editorGenerationSettled && mediaProviderCurrent && /* @__PURE__ */ jsx21(EditorErrorBoundary, { resetKey: `${selectedFile}-${editorKey}`, children: /* @__PURE__ */ jsx21(
11847
12134
  EditorShell,
11848
12135
  {
11849
12136
  initialMarkdown: editorContent,
@@ -11894,19 +12181,19 @@ function DocBlocksShell({
11894
12181
  versioningAutoSaveIdleMs,
11895
12182
  onSaveVersion,
11896
12183
  statusBarSlotRight,
11897
- sidePanelSlot: ai && aiPanel && selectedImage === void 0 && (selectedOutsideIn === null || selectedOutsideInEditingEnabled) ? /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: aiPanel === "review" ? /* @__PURE__ */ jsx19(AiReviewPanel, { ai, onClose: () => setAiPanel(null) }) : /* @__PURE__ */ jsx19(AiIllustratePanel, { ai, onClose: () => setAiPanel(null) }) }) : void 0,
11898
- toolbarSlotLeft: singlePane ? /* @__PURE__ */ jsx19(
12184
+ sidePanelSlot: ai && aiPanel && selectedImage === void 0 && (selectedOutsideIn === null || selectedOutsideInEditingEnabled) ? /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: aiPanel === "review" ? /* @__PURE__ */ jsx21(AiReviewPanel, { ai, onClose: () => setAiPanel(null) }) : aiPanel === "images" ? /* @__PURE__ */ jsx21(AiImagePanel, { ai, onClose: () => setAiPanel(null) }) : /* @__PURE__ */ jsx21(AiIllustratePanel, { ai, onClose: () => setAiPanel(null) }) }) : void 0,
12185
+ toolbarSlotLeft: singlePane ? /* @__PURE__ */ jsx21(
11899
12186
  "button",
11900
12187
  {
11901
12188
  className: "db-mobile-back",
11902
12189
  onClick: () => setMobileShowEditor(false),
11903
12190
  "aria-label": "Show file list",
11904
- children: /* @__PURE__ */ jsx19("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx19(FolderGlyph, {}) })
12191
+ children: /* @__PURE__ */ jsx21("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx21(FolderGlyph, {}) })
11905
12192
  }
11906
12193
  ) : void 0,
11907
- summarizationDesigner: selectedImage === void 0 && selectedManagedOutput === void 0 && (selectedOutsideIn === null || selectedOutsideInEditingEnabled) ? (onClose) => /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx19(PresentationMaker, { ai: ai ?? void 0, onClose }) }) : void 0,
11908
- toolbarSlotRight: /* @__PURE__ */ jsxs17(Fragment11, { children: [
11909
- canFind && /* @__PURE__ */ jsx19(
12194
+ summarizationDesigner: selectedImage === void 0 && selectedManagedOutput === void 0 && (selectedOutsideIn === null || selectedOutsideInEditingEnabled) ? (onClose) => /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx21(PresentationMaker, { ai: ai ?? void 0, onClose }) }) : void 0,
12195
+ toolbarSlotRight: /* @__PURE__ */ jsxs19(Fragment12, { children: [
12196
+ canFind && /* @__PURE__ */ jsx21(
11910
12197
  FindButton,
11911
12198
  {
11912
12199
  active: findMode,
@@ -11914,7 +12201,7 @@ function DocBlocksShell({
11914
12201
  shortcutLabel: findShortcut
11915
12202
  }
11916
12203
  ),
11917
- ai && /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx19(
12204
+ ai && /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx21(
11918
12205
  AiToolbarControl,
11919
12206
  {
11920
12207
  ai,
@@ -11923,38 +12210,38 @@ function DocBlocksShell({
11923
12210
  onOpenPanel: setAiPanel
11924
12211
  }
11925
12212
  ) }),
11926
- speech && /* @__PURE__ */ jsxs17(Suspense2, { fallback: null, children: [
11927
- /* @__PURE__ */ jsx19(
12213
+ speech && /* @__PURE__ */ jsxs19(Suspense2, { fallback: null, children: [
12214
+ /* @__PURE__ */ jsx21(
11928
12215
  TextFromNarration,
11929
12216
  {
11930
12217
  speech,
11931
12218
  ai: ai ?? void 0,
11932
12219
  allowRecording,
11933
12220
  readOnly: selectedImage !== void 0 || selectedManagedOutput !== void 0 || selectedOutsideIn !== null && !selectedOutsideInEditingEnabled,
11934
- onOpenSettings: openSettings
12221
+ onOpenSettings: openDictationSettings
11935
12222
  }
11936
12223
  ),
11937
- hostSupports2("speechOutput") ? /* @__PURE__ */ jsx19(
12224
+ hostSupports3("speechOutput") ? /* @__PURE__ */ jsx21(
11938
12225
  SpeechToolbarControl,
11939
12226
  {
11940
12227
  speech,
11941
- onOpenSettings: openSettings,
12228
+ onOpenSettings: openNarrationSettings,
11942
12229
  readOnly: selectedImage !== void 0 || selectedOutsideIn !== null && !selectedOutsideInEditingEnabled
11943
12230
  }
11944
- ) : /* @__PURE__ */ jsx19(SpeechMenuBridge, {})
12231
+ ) : /* @__PURE__ */ jsx21(SpeechMenuBridge, {})
11945
12232
  ] }),
11946
- canRestoreSplitView && /* @__PURE__ */ jsx19(
12233
+ canRestoreSplitView && /* @__PURE__ */ jsx21(
11947
12234
  "button",
11948
12235
  {
11949
12236
  className: "db-restore-split",
11950
12237
  onClick: () => updateSidebarPreference("pinned"),
11951
12238
  "aria-label": "Restore split view",
11952
12239
  title: "Restore split view",
11953
- children: /* @__PURE__ */ jsx19(SplitViewIcon, {})
12240
+ children: /* @__PURE__ */ jsx21(SplitViewIcon, {})
11954
12241
  }
11955
12242
  ),
11956
- git.repo && /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx19(GitToolbarControl, { selectedFile }) }),
11957
- /* @__PURE__ */ jsx19(
12243
+ git.repo && /* @__PURE__ */ jsx21(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx21(GitToolbarControl, { selectedFile }) }),
12244
+ /* @__PURE__ */ jsx21(
11958
12245
  ExportToolbarControls,
11959
12246
  {
11960
12247
  selectedFile,
@@ -11978,39 +12265,39 @@ function DocBlocksShell({
11978
12265
  }
11979
12266
  )
11980
12267
  }
11981
- ) }) : selectedFolder ? /* @__PURE__ */ jsxs17("div", { className: "db-folder-view", children: [
11982
- singlePane && /* @__PURE__ */ jsxs17("button", { className: "db-mobile-back", onClick: () => setMobileShowEditor(false), children: [
11983
- /* @__PURE__ */ jsx19("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx19(FolderGlyph, {}) }),
12268
+ ) }) : selectedFolder ? /* @__PURE__ */ jsxs19("div", { className: "db-folder-view", children: [
12269
+ singlePane && /* @__PURE__ */ jsxs19("button", { className: "db-mobile-back", onClick: () => setMobileShowEditor(false), children: [
12270
+ /* @__PURE__ */ jsx21("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx21(FolderGlyph, {}) }),
11984
12271
  "Back to files"
11985
12272
  ] }),
11986
- /* @__PURE__ */ jsxs17("div", { className: "db-folder-view-header", children: [
11987
- /* @__PURE__ */ jsx19("span", { className: "db-folder-view-icon", children: /* @__PURE__ */ jsx19(FolderGlyph, {}) }),
11988
- /* @__PURE__ */ jsx19("span", { className: "db-folder-view-path", children: selectedFolder })
12273
+ /* @__PURE__ */ jsxs19("div", { className: "db-folder-view-header", children: [
12274
+ /* @__PURE__ */ jsx21("span", { className: "db-folder-view-icon", children: /* @__PURE__ */ jsx21(FolderGlyph, {}) }),
12275
+ /* @__PURE__ */ jsx21("span", { className: "db-folder-view-path", children: selectedFolder })
11989
12276
  ] }),
11990
- visibleFolderEntries.length === 0 ? /* @__PURE__ */ jsx19("p", { className: "db-folder-view-empty", children: "This folder is empty." }) : /* @__PURE__ */ jsx19("ul", { className: "db-folder-view-list", children: visibleFolderEntries.map((entry) => /* @__PURE__ */ jsxs17(
12277
+ visibleFolderEntries.length === 0 ? /* @__PURE__ */ jsx21("p", { className: "db-folder-view-empty", children: "This folder is empty." }) : /* @__PURE__ */ jsx21("ul", { className: "db-folder-view-list", children: visibleFolderEntries.map((entry) => /* @__PURE__ */ jsxs19(
11991
12278
  "li",
11992
12279
  {
11993
12280
  className: "db-folder-view-item",
11994
12281
  onClick: () => handleSelect(entry.path, entry.kind),
11995
12282
  children: [
11996
- /* @__PURE__ */ jsx19("span", { className: "db-folder-view-item-icon", children: entry.kind === "directory" ? /* @__PURE__ */ jsx19(FolderGlyph, {}) : /* @__PURE__ */ jsx19(FileGlyph, {}) }),
12283
+ /* @__PURE__ */ jsx21("span", { className: "db-folder-view-item-icon", children: entry.kind === "directory" ? /* @__PURE__ */ jsx21(FolderGlyph, {}) : /* @__PURE__ */ jsx21(FileGlyph, {}) }),
11997
12284
  entry.name
11998
12285
  ]
11999
12286
  },
12000
12287
  entry.path
12001
12288
  )) })
12002
- ] }) : /* @__PURE__ */ jsxs17("div", { className: "db-shell-empty db-shell-empty--workspace", children: [
12003
- singlePane && /* @__PURE__ */ jsxs17("button", { className: "db-mobile-back", onClick: () => setMobileShowEditor(false), children: [
12004
- /* @__PURE__ */ jsx19("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx19(FolderGlyph, {}) }),
12289
+ ] }) : /* @__PURE__ */ jsxs19("div", { className: "db-shell-empty db-shell-empty--workspace", children: [
12290
+ singlePane && /* @__PURE__ */ jsxs19("button", { className: "db-mobile-back", onClick: () => setMobileShowEditor(false), children: [
12291
+ /* @__PURE__ */ jsx21("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx21(FolderGlyph, {}) }),
12005
12292
  "Back to files"
12006
12293
  ] }),
12007
- /* @__PURE__ */ jsxs17("div", { className: "db-workspace-empty-content", children: [
12008
- /* @__PURE__ */ jsx19("span", { className: "db-workspace-empty-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx19(FileGlyph, {}) }),
12009
- /* @__PURE__ */ jsx19("h1", { children: activeWorkspaceDescriptor?.name ?? "Workspace" }),
12010
- /* @__PURE__ */ jsx19("p", { children: "Choose a Markdown document from the sidebar, or create a new one." }),
12011
- /* @__PURE__ */ jsxs17("div", { className: "db-workspace-empty-actions", children: [
12012
- /* @__PURE__ */ jsx19("button", { type: "button", onClick: () => void handleNewFile(), children: "New document" }),
12013
- /* @__PURE__ */ jsx19(
12294
+ /* @__PURE__ */ jsxs19("div", { className: "db-workspace-empty-content", children: [
12295
+ /* @__PURE__ */ jsx21("span", { className: "db-workspace-empty-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx21(FileGlyph, {}) }),
12296
+ /* @__PURE__ */ jsx21("h1", { children: activeWorkspaceDescriptor?.name ?? "Workspace" }),
12297
+ /* @__PURE__ */ jsx21("p", { children: "Choose a Markdown document from the sidebar, or create a new one." }),
12298
+ /* @__PURE__ */ jsxs19("div", { className: "db-workspace-empty-actions", children: [
12299
+ /* @__PURE__ */ jsx21("button", { type: "button", onClick: () => void handleNewFile(), children: "New document" }),
12300
+ /* @__PURE__ */ jsx21(
12014
12301
  "button",
12015
12302
  {
12016
12303
  type: "button",
@@ -12019,7 +12306,7 @@ function DocBlocksShell({
12019
12306
  children: "New folder"
12020
12307
  }
12021
12308
  ),
12022
- (hostSupports2("workspaceFolderPicker") || typeof globalThis.showDirectoryPicker === "function") && /* @__PURE__ */ jsx19(
12309
+ (hostSupports3("workspaceFolderPicker") || typeof globalThis.showDirectoryPicker === "function") && /* @__PURE__ */ jsx21(
12023
12310
  "button",
12024
12311
  {
12025
12312
  type: "button",
@@ -12029,10 +12316,10 @@ function DocBlocksShell({
12029
12316
  }
12030
12317
  )
12031
12318
  ] }),
12032
- showBrowserStorageWarning && /* @__PURE__ */ jsx19("p", { className: "db-workspace-empty-hint", children: "Use the sidebar backup action to keep a portable copy of this workspace." })
12319
+ showBrowserStorageWarning && /* @__PURE__ */ jsx21("p", { className: "db-workspace-empty-hint", children: "Use the sidebar backup action to keep a portable copy of this workspace." })
12033
12320
  ] })
12034
12321
  ] }),
12035
- /* @__PURE__ */ jsx19(
12322
+ /* @__PURE__ */ jsx21(
12036
12323
  UpdateAvailableNotice,
12037
12324
  {
12038
12325
  available: updateAvailable,
@@ -12042,7 +12329,7 @@ function DocBlocksShell({
12042
12329
  }
12043
12330
  )
12044
12331
  ] }),
12045
- welcomeScreenShown && /* @__PURE__ */ jsx19(
12332
+ welcomeScreenShown && /* @__PURE__ */ jsx21(
12046
12333
  WelcomeScreen,
12047
12334
  {
12048
12335
  onCreateDocument: handleNewFile,