@bendyline/docblocks-react 2.2.2 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -33,11 +33,13 @@ import {
33
33
  } from "./chunk-JDJVRDOP.js";
34
34
  import {
35
35
  ExportDialog
36
- } from "./chunk-MHTQORMH.js";
36
+ } from "./chunk-SIIEGOHY.js";
37
37
  import {
38
- buildExportFilename,
39
38
  runExport
40
- } from "./chunk-GHQ4X7KM.js";
39
+ } from "./chunk-OSQUKIUN.js";
40
+ import {
41
+ createBrowserSaveAsAdapter
42
+ } from "./chunk-UMEDHMT7.js";
41
43
  import {
42
44
  useMenuKeyboard
43
45
  } from "./chunk-MRUK56JS.js";
@@ -45,6 +47,9 @@ import "./chunk-YBEYTVU2.js";
45
47
  import {
46
48
  Dialog
47
49
  } from "./chunk-LG6HAWCK.js";
50
+ import {
51
+ buildExportFilename
52
+ } from "./chunk-M5Y5WO7Z.js";
48
53
  import {
49
54
  DEFAULT_OPTIONS,
50
55
  loadLastExportOptions
@@ -64,7 +69,8 @@ import {
64
69
  fsErrorFromUnknown,
65
70
  getFileSystemProviderV2,
66
71
  moveFileSystemEntry,
67
- parseWorkspacePath
72
+ parseWorkspacePath,
73
+ workspacePathDirname
68
74
  } from "@bendyline/docblocks/filesystem";
69
75
  var DIRECTORY_NOT_FOUND_RETRY_DELAYS_MS = Object.freeze([40, 120]);
70
76
  function normalisePath(path) {
@@ -97,7 +103,12 @@ async function readProviderDirectory(provider, path) {
97
103
  const providerV2 = getFileSystemProviderV2(provider);
98
104
  if (!providerV2) return provider.readDirectory(path);
99
105
  const entries = await providerV2.readDirectory(canonical);
100
- return entries.map((entry) => ({ kind: entry.kind, name: entry.name, path: entry.path }));
106
+ return entries.map((entry) => ({
107
+ kind: entry.kind,
108
+ name: entry.name,
109
+ path: entry.path,
110
+ ...entry.kind === "file" ? { lastModified: entry.lastModified } : {}
111
+ }));
101
112
  };
102
113
  for (let attempt = 0; ; attempt += 1) {
103
114
  try {
@@ -131,7 +142,7 @@ function readIssue(caught, directoryPath) {
131
142
  retryable: error.retryable || error.code === "not-found"
132
143
  });
133
144
  }
134
- function useFileTree(provider) {
145
+ function useFileTree(provider, metadataRefreshKey, metadataRefreshPath) {
135
146
  const [entries, setEntries] = useState([]);
136
147
  const [expanded, setExpanded] = useState(/* @__PURE__ */ new Set());
137
148
  const [selectedPath, setSelectedPath] = useState(null);
@@ -147,7 +158,7 @@ function useFileTree(provider) {
147
158
  const reportRootIssue = useCallback((caught) => {
148
159
  setRootIssue(readIssue(caught, ""));
149
160
  }, []);
150
- const loadRoot = useCallback(async () => {
161
+ const loadRoot = useCallback(async (showLoading = true) => {
151
162
  const sourceProvider = providerRef.current;
152
163
  if (!sourceProvider) {
153
164
  setEntries([]);
@@ -157,7 +168,7 @@ function useFileTree(provider) {
157
168
  const requestId = ++directoryRequestSequenceRef.current;
158
169
  directoryRequestsRef.current.set("", requestId);
159
170
  const isCurrent = () => providerRef.current === sourceProvider && directoryRequestsRef.current.get("") === requestId;
160
- setLoading(true);
171
+ if (showLoading) setLoading(true);
161
172
  try {
162
173
  const root = await readProviderDirectory(sourceProvider, "");
163
174
  if (!isCurrent()) return;
@@ -263,37 +274,76 @@ function useFileTree(provider) {
263
274
  );
264
275
  const refreshRef = useRef(refresh);
265
276
  refreshRef.current = refresh;
277
+ const refreshDirectory = useCallback(
278
+ async (directoryPath) => {
279
+ if (directoryPath === "") await loadRoot(false);
280
+ else await loadChildren(directoryPath);
281
+ },
282
+ [loadChildren, loadRoot]
283
+ );
284
+ const previousMetadataRefreshKeyRef = useRef(metadataRefreshKey);
285
+ useEffect(() => {
286
+ if (Object.is(previousMetadataRefreshKeyRef.current, metadataRefreshKey)) return;
287
+ previousMetadataRefreshKeyRef.current = metadataRefreshKey;
288
+ if (!provider) return;
289
+ if (getFileSystemProviderV2(provider)?.capabilities.watch) return;
290
+ const directoryPath = metadataRefreshPath ? workspacePathDirname(parseWorkspacePath(metadataRefreshPath)) : "";
291
+ void refreshDirectory(directoryPath).catch(reportRootIssue);
292
+ }, [metadataRefreshKey, metadataRefreshPath, provider, refreshDirectory, reportRootIssue]);
266
293
  useEffect(() => {
267
294
  if (!provider) return;
268
295
  const providerV2 = getFileSystemProviderV2(provider);
269
296
  if (!providerV2?.capabilities.watch) return;
270
297
  let disposed = false;
271
298
  let refreshing = false;
272
- let refreshAgain = false;
273
- const requestRefresh = () => {
299
+ let fullRefreshRequested = false;
300
+ const directoriesToRefresh = /* @__PURE__ */ new Set();
301
+ const drainRefreshes = () => {
274
302
  if (disposed) return;
275
- if (refreshing) {
276
- refreshAgain = true;
277
- return;
278
- }
303
+ if (refreshing) return;
279
304
  refreshing = true;
280
305
  void (async () => {
281
306
  try {
282
- do {
283
- refreshAgain = false;
284
- await refreshRef.current();
285
- } while (refreshAgain && !disposed);
307
+ while (!disposed && (fullRefreshRequested || directoriesToRefresh.size > 0)) {
308
+ if (fullRefreshRequested) {
309
+ fullRefreshRequested = false;
310
+ directoriesToRefresh.clear();
311
+ await refreshRef.current();
312
+ continue;
313
+ }
314
+ const pending = [...directoriesToRefresh];
315
+ directoriesToRefresh.clear();
316
+ for (const directoryPath of pending) {
317
+ await refreshDirectory(directoryPath);
318
+ }
319
+ }
286
320
  } catch (caught) {
287
321
  reportRootIssue(caught);
288
322
  } finally {
289
323
  refreshing = false;
290
- if (refreshAgain && !disposed) requestRefresh();
324
+ if (!disposed && (fullRefreshRequested || directoriesToRefresh.size > 0)) {
325
+ drainRefreshes();
326
+ }
291
327
  }
292
328
  })();
293
329
  };
330
+ const requestRefresh = () => {
331
+ if (disposed) return;
332
+ fullRefreshRequested = true;
333
+ directoriesToRefresh.clear();
334
+ drainRefreshes();
335
+ };
336
+ const requestMetadataRefresh = (path) => {
337
+ if (disposed || fullRefreshRequested) return;
338
+ directoriesToRefresh.add(workspacePathDirname(parseWorkspacePath(path)));
339
+ drainRefreshes();
340
+ };
294
341
  const subscription = providerV2.watch(
295
342
  (event) => {
296
- if (event.type === "modified") return;
343
+ if (event.type === "modified") {
344
+ requestMetadataRefresh(event.path);
345
+ return;
346
+ }
297
347
  requestRefresh();
298
348
  },
299
349
  {
@@ -311,7 +361,7 @@ function useFileTree(provider) {
311
361
  disposed = true;
312
362
  void subscription.dispose();
313
363
  };
314
- }, [provider, reportRootIssue]);
364
+ }, [provider, refreshDirectory, reportRootIssue]);
315
365
  useEffect(() => {
316
366
  if (!provider) return;
317
367
  const providerV2 = getFileSystemProviderV2(provider);
@@ -448,6 +498,12 @@ function NewFileIcon() {
448
498
  function NewFolderIcon() {
449
499
  return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-folder-plus" });
450
500
  }
501
+ function SortByNameIcon() {
502
+ return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-arrow-down-a-z" });
503
+ }
504
+ function SortByLastModifiedIcon() {
505
+ return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-clock" });
506
+ }
451
507
  function FolderIcon() {
452
508
  return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-folder" });
453
509
  }
@@ -481,8 +537,116 @@ function SplitViewIcon() {
481
537
  );
482
538
  }
483
539
 
540
+ // src/FileExplorer/LastModifiedTime.tsx
541
+ import { useSyncExternalStore } from "react";
542
+
543
+ // src/FileExplorer/last-modified.ts
544
+ var MINUTE_MS = 6e4;
545
+ var HOUR_MS = 60 * MINUTE_MS;
546
+ var DAY_MS = 24 * HOUR_MS;
547
+ var shortDateFormatter = new Intl.DateTimeFormat(void 0, {
548
+ month: "short",
549
+ day: "numeric"
550
+ });
551
+ var shortDateWithYearFormatter = new Intl.DateTimeFormat(void 0, {
552
+ year: "numeric",
553
+ month: "short",
554
+ day: "numeric"
555
+ });
556
+ var fullDateTimeFormatter = new Intl.DateTimeFormat(void 0, {
557
+ dateStyle: "medium",
558
+ timeStyle: "short"
559
+ });
560
+ function plural(value, unit) {
561
+ return `${value} ${unit}${value === 1 ? "" : "s"} ago`;
562
+ }
563
+ function formatFriendlyLastModified(value, now = Date.now()) {
564
+ if (!value) return null;
565
+ const timestamp = Date.parse(value);
566
+ if (!Number.isFinite(timestamp)) return null;
567
+ const date = new Date(timestamp);
568
+ const elapsed = now - timestamp;
569
+ const title = `Last modified ${fullDateTimeFormatter.format(date)}`;
570
+ if (elapsed >= -MINUTE_MS && elapsed < MINUTE_MS) {
571
+ return { shortLabel: "Now", accessibleLabel: "Last modified just now", title };
572
+ }
573
+ if (elapsed >= 0 && elapsed < HOUR_MS) {
574
+ const minutes = Math.max(1, Math.floor(elapsed / MINUTE_MS));
575
+ return {
576
+ shortLabel: `${minutes}m ago`,
577
+ accessibleLabel: `Last modified ${plural(minutes, "minute")}`,
578
+ title
579
+ };
580
+ }
581
+ if (elapsed >= 0 && elapsed < DAY_MS) {
582
+ const hours = Math.max(1, Math.floor(elapsed / HOUR_MS));
583
+ return {
584
+ shortLabel: `${hours}h ago`,
585
+ accessibleLabel: `Last modified ${plural(hours, "hour")}`,
586
+ title
587
+ };
588
+ }
589
+ if (elapsed >= DAY_MS && elapsed < 2 * DAY_MS) {
590
+ return { shortLabel: "Yesterday", accessibleLabel: "Last modified yesterday", title };
591
+ }
592
+ if (elapsed >= 2 * DAY_MS && elapsed < 7 * DAY_MS) {
593
+ const days = Math.floor(elapsed / DAY_MS);
594
+ return {
595
+ shortLabel: `${days}d ago`,
596
+ accessibleLabel: `Last modified ${plural(days, "day")}`,
597
+ title
598
+ };
599
+ }
600
+ const currentYear = new Date(now).getFullYear();
601
+ const shortLabel = date.getFullYear() === currentYear ? shortDateFormatter.format(date) : shortDateWithYearFormatter.format(date);
602
+ return { shortLabel, accessibleLabel: title, title };
603
+ }
604
+
605
+ // src/FileExplorer/LastModifiedTime.tsx
606
+ import { jsx as jsx2 } from "react/jsx-runtime";
607
+ var CLOCK_INTERVAL_MS = 6e4;
608
+ var clockNow = Date.now();
609
+ var clockTimer = null;
610
+ var clockListeners = /* @__PURE__ */ new Set();
611
+ function publishClockTick() {
612
+ clockNow = Date.now();
613
+ for (const listener of clockListeners) listener();
614
+ }
615
+ function subscribeToClock(listener) {
616
+ clockListeners.add(listener);
617
+ if (clockListeners.size === 1) {
618
+ clockNow = Date.now();
619
+ clockTimer = globalThis.setInterval(publishClockTick, CLOCK_INTERVAL_MS);
620
+ }
621
+ return () => {
622
+ clockListeners.delete(listener);
623
+ if (clockListeners.size === 0 && clockTimer !== null) {
624
+ globalThis.clearInterval(clockTimer);
625
+ clockTimer = null;
626
+ }
627
+ };
628
+ }
629
+ function getClockSnapshot() {
630
+ return clockNow;
631
+ }
632
+ function LastModifiedTime({ value }) {
633
+ const now = useSyncExternalStore(subscribeToClock, getClockSnapshot, getClockSnapshot);
634
+ const lastModified = formatFriendlyLastModified(value, now);
635
+ if (!lastModified) return null;
636
+ return /* @__PURE__ */ jsx2(
637
+ "time",
638
+ {
639
+ className: "db-tree-last-modified",
640
+ dateTime: value,
641
+ title: lastModified.title,
642
+ "aria-label": lastModified.accessibleLabel,
643
+ children: lastModified.shortLabel
644
+ }
645
+ );
646
+ }
647
+
484
648
  // src/FileExplorer/FileTreeNode.tsx
485
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
649
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
486
650
  function defaultConfirmDelete(message) {
487
651
  if (typeof window === "undefined") return false;
488
652
  return window.confirm(message);
@@ -769,8 +933,8 @@ function FileTreeNode({
769
933
  }
770
934
  },
771
935
  children: [
772
- (isDir || depth === 0) && /* @__PURE__ */ jsx2("span", { className: "db-tree-icon", children: isDir ? icon : null }),
773
- renaming ? /* @__PURE__ */ jsx2(
936
+ (isDir || depth === 0) && /* @__PURE__ */ jsx3("span", { className: "db-tree-icon", children: isDir ? icon : null }),
937
+ renaming ? /* @__PURE__ */ jsx3(
774
938
  "input",
775
939
  {
776
940
  ref: inputRef,
@@ -788,9 +952,10 @@ function FileTreeNode({
788
952
  onClick: (e) => e.stopPropagation()
789
953
  }
790
954
  ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
791
- /* @__PURE__ */ jsx2("span", { className: "db-tree-label", children: entry.name.endsWith(".md") ? entry.name.slice(0, -3) : entry.name }),
792
- badge && /* @__PURE__ */ jsx2("span", { className: `db-git-badge db-git-badge--${badge.kind}`, "aria-hidden": "true", children: badge.glyph }),
793
- /* @__PURE__ */ jsx2(
955
+ /* @__PURE__ */ jsx3("span", { className: "db-tree-label", children: entry.name.endsWith(".md") ? entry.name.slice(0, -3) : entry.name }),
956
+ badge && /* @__PURE__ */ jsx3("span", { className: `db-git-badge db-git-badge--${badge.kind}`, "aria-hidden": "true", children: badge.glyph }),
957
+ entry.kind === "file" && entry.lastModified && /* @__PURE__ */ jsx3(LastModifiedTime, { value: entry.lastModified }),
958
+ /* @__PURE__ */ jsx3(
794
959
  "button",
795
960
  {
796
961
  type: "button",
@@ -803,14 +968,14 @@ function FileTreeNode({
803
968
  "aria-keyshortcuts": "Shift+F10",
804
969
  title: "More actions (Shift+F10)",
805
970
  tabIndex: -1,
806
- children: /* @__PURE__ */ jsx2(MoreIcon, {})
971
+ children: /* @__PURE__ */ jsx3(MoreIcon, {})
807
972
  }
808
973
  )
809
974
  ] })
810
975
  ]
811
976
  }
812
977
  ),
813
- actionError && /* @__PURE__ */ jsx2("div", { className: "db-tree-error", role: "alert", children: actionError }),
978
+ actionError && /* @__PURE__ */ jsx3("div", { className: "db-tree-error", role: "alert", children: actionError }),
814
979
  showContext && createPortal(
815
980
  /* @__PURE__ */ jsxs2(
816
981
  "div",
@@ -822,7 +987,7 @@ function FileTreeNode({
822
987
  "aria-label": `Actions for ${entry.name}`,
823
988
  onKeyDown: handleMenuKeyDown,
824
989
  children: [
825
- /* @__PURE__ */ jsx2(
990
+ /* @__PURE__ */ jsx3(
826
991
  "button",
827
992
  {
828
993
  type: "button",
@@ -833,7 +998,7 @@ function FileTreeNode({
833
998
  children: "Rename"
834
999
  }
835
1000
  ),
836
- !isDir && onTogglePin && /* @__PURE__ */ jsx2(
1001
+ !isDir && onTogglePin && /* @__PURE__ */ jsx3(
837
1002
  "button",
838
1003
  {
839
1004
  type: "button",
@@ -845,8 +1010,8 @@ function FileTreeNode({
845
1010
  }
846
1011
  ),
847
1012
  gitActions && (gitActions.viewChanges || gitActions.fileHistory) && /* @__PURE__ */ jsxs2(Fragment, { children: [
848
- /* @__PURE__ */ jsx2("div", { className: "db-tree-context-divider", role: "separator" }),
849
- gitActions.viewChanges && /* @__PURE__ */ jsx2(
1013
+ /* @__PURE__ */ jsx3("div", { className: "db-tree-context-divider", role: "separator" }),
1014
+ gitActions.viewChanges && /* @__PURE__ */ jsx3(
850
1015
  "button",
851
1016
  {
852
1017
  type: "button",
@@ -860,7 +1025,7 @@ function FileTreeNode({
860
1025
  children: "View changes"
861
1026
  }
862
1027
  ),
863
- gitActions.fileHistory && /* @__PURE__ */ jsx2(
1028
+ gitActions.fileHistory && /* @__PURE__ */ jsx3(
864
1029
  "button",
865
1030
  {
866
1031
  type: "button",
@@ -874,7 +1039,7 @@ function FileTreeNode({
874
1039
  children: "File history\u2026"
875
1040
  }
876
1041
  ),
877
- gitActions.openOnRemote && /* @__PURE__ */ jsx2(
1042
+ gitActions.openOnRemote && /* @__PURE__ */ jsx3(
878
1043
  "button",
879
1044
  {
880
1045
  type: "button",
@@ -888,9 +1053,9 @@ function FileTreeNode({
888
1053
  children: "Open on remote"
889
1054
  }
890
1055
  ),
891
- /* @__PURE__ */ jsx2("div", { className: "db-tree-context-divider", role: "separator" })
1056
+ /* @__PURE__ */ jsx3("div", { className: "db-tree-context-divider", role: "separator" })
892
1057
  ] }),
893
- /* @__PURE__ */ jsx2(
1058
+ /* @__PURE__ */ jsx3(
894
1059
  "button",
895
1060
  {
896
1061
  type: "button",
@@ -906,7 +1071,7 @@ function FileTreeNode({
906
1071
  ),
907
1072
  document.body
908
1073
  ),
909
- isDir && expanded && renderChildren && /* @__PURE__ */ jsx2("div", { className: "db-tree-children", role: "group", children: renderChildren(entry.path) }),
1074
+ isDir && expanded && renderChildren && /* @__PURE__ */ jsx3("div", { className: "db-tree-children", role: "group", children: renderChildren(entry.path) }),
910
1075
  isDir && expanded && childError
911
1076
  ] });
912
1077
  }
@@ -1096,7 +1261,7 @@ function movePinnedDocumentsToWorkspace(documents, sourceWorkspaceId, destinatio
1096
1261
  }
1097
1262
 
1098
1263
  // src/FileExplorer/PinnedDocuments.tsx
1099
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1264
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1100
1265
  function displayName(document2) {
1101
1266
  const name = pinnedDocumentName(document2);
1102
1267
  return name.endsWith(".md") ? name.slice(0, -3) : name;
@@ -1240,7 +1405,7 @@ function PinnedDocumentRow({
1240
1405
  }));
1241
1406
  }, [showContext]);
1242
1407
  return /* @__PURE__ */ jsxs3("div", { className: `db-pinned-document-row${selected ? " db-pinned-document-row--selected" : ""}`, children: [
1243
- /* @__PURE__ */ jsx3(
1408
+ /* @__PURE__ */ jsx4(
1244
1409
  "button",
1245
1410
  {
1246
1411
  ref: selectRef,
@@ -1259,12 +1424,12 @@ function PinnedDocumentRow({
1259
1424
  }
1260
1425
  },
1261
1426
  children: /* @__PURE__ */ jsxs3("span", { className: "db-pinned-document-heading", children: [
1262
- /* @__PURE__ */ jsx3("span", { className: "db-pinned-document-name", children: displayName(pinnedDocument) }),
1263
- missing && /* @__PURE__ */ jsx3("span", { className: "db-pinned-document-missing", children: "(missing)" })
1427
+ /* @__PURE__ */ jsx4("span", { className: "db-pinned-document-name", children: displayName(pinnedDocument) }),
1428
+ missing && /* @__PURE__ */ jsx4("span", { className: "db-pinned-document-missing", children: "(missing)" })
1264
1429
  ] })
1265
1430
  }
1266
1431
  ),
1267
- hasActions && /* @__PURE__ */ jsx3(
1432
+ hasActions && /* @__PURE__ */ jsx4(
1268
1433
  "button",
1269
1434
  {
1270
1435
  type: "button",
@@ -1275,10 +1440,10 @@ function PinnedDocumentRow({
1275
1440
  title: "More actions",
1276
1441
  onClick: handleMoreClick,
1277
1442
  onContextMenu: handleMoreClick,
1278
- children: /* @__PURE__ */ jsx3(MoreIcon, {})
1443
+ children: /* @__PURE__ */ jsx4(MoreIcon, {})
1279
1444
  }
1280
1445
  ),
1281
- actionError && /* @__PURE__ */ jsx3("div", { className: "db-tree-error db-pinned-document-error", role: "alert", children: actionError }),
1446
+ actionError && /* @__PURE__ */ jsx4("div", { className: "db-tree-error db-pinned-document-error", role: "alert", children: actionError }),
1282
1447
  showContext && createPortal2(
1283
1448
  /* @__PURE__ */ jsxs3(
1284
1449
  "div",
@@ -1290,7 +1455,7 @@ function PinnedDocumentRow({
1290
1455
  "aria-label": `Actions for ${name}`,
1291
1456
  onKeyDown: handleMenuKeyDown,
1292
1457
  children: [
1293
- onRename && /* @__PURE__ */ jsx3(
1458
+ onRename && /* @__PURE__ */ jsx4(
1294
1459
  "button",
1295
1460
  {
1296
1461
  type: "button",
@@ -1301,7 +1466,7 @@ function PinnedDocumentRow({
1301
1466
  children: "Rename"
1302
1467
  }
1303
1468
  ),
1304
- onUnpin && /* @__PURE__ */ jsx3(
1469
+ onUnpin && /* @__PURE__ */ jsx4(
1305
1470
  "button",
1306
1471
  {
1307
1472
  type: "button",
@@ -1312,8 +1477,8 @@ function PinnedDocumentRow({
1312
1477
  children: "Unpin"
1313
1478
  }
1314
1479
  ),
1315
- onDelete && (onRename || onUnpin) && /* @__PURE__ */ jsx3("div", { className: "db-tree-context-divider", role: "separator" }),
1316
- onDelete && /* @__PURE__ */ jsx3(
1480
+ onDelete && (onRename || onUnpin) && /* @__PURE__ */ jsx4("div", { className: "db-tree-context-divider", role: "separator" }),
1481
+ onDelete && /* @__PURE__ */ jsx4(
1317
1482
  "button",
1318
1483
  {
1319
1484
  type: "button",
@@ -1344,10 +1509,10 @@ function PinnedDocuments({
1344
1509
  if (documents.length === 0) return null;
1345
1510
  return /* @__PURE__ */ jsxs3("section", { className: "db-pinned-documents", "aria-labelledby": titleId, children: [
1346
1511
  /* @__PURE__ */ jsxs3("h2", { id: titleId, className: "db-explorer-title db-pinned-documents-title", children: [
1347
- /* @__PURE__ */ jsx3(PinIcon, {}),
1348
- /* @__PURE__ */ jsx3("span", { children: "Pinned" })
1512
+ /* @__PURE__ */ jsx4(PinIcon, {}),
1513
+ /* @__PURE__ */ jsx4("span", { children: "Pinned" })
1349
1514
  ] }),
1350
- /* @__PURE__ */ jsx3("div", { className: "db-pinned-document-list", children: documents.map((document2) => /* @__PURE__ */ jsx3(
1515
+ /* @__PURE__ */ jsx4("div", { className: "db-pinned-document-list", children: documents.map((document2) => /* @__PURE__ */ jsx4(
1351
1516
  PinnedDocumentRow,
1352
1517
  {
1353
1518
  document: document2,
@@ -1372,8 +1537,34 @@ function filterVisibleFileEntries(entries) {
1372
1537
  return entries.filter((entry) => !isHiddenFileEntry(entry));
1373
1538
  }
1374
1539
 
1540
+ // src/FileExplorer/entry-sort.ts
1541
+ function compareText(left, right) {
1542
+ return left < right ? -1 : left > right ? 1 : 0;
1543
+ }
1544
+ function modifiedTime(entry) {
1545
+ if (entry.kind !== "file" || !entry.lastModified) return null;
1546
+ const timestamp = Date.parse(entry.lastModified);
1547
+ return Number.isNaN(timestamp) ? null : timestamp;
1548
+ }
1549
+ function sortFileEntries(entries, mode) {
1550
+ return [...entries].sort((left, right) => {
1551
+ if (left.kind !== right.kind) return left.kind === "directory" ? -1 : 1;
1552
+ if (left.kind === "directory" || right.kind === "directory" || mode === "name") {
1553
+ return compareText(left.name, right.name);
1554
+ }
1555
+ const leftTime = modifiedTime(left);
1556
+ const rightTime = modifiedTime(right);
1557
+ if (leftTime !== null && rightTime !== null && leftTime !== rightTime) {
1558
+ return rightTime - leftTime;
1559
+ }
1560
+ if (leftTime === null && rightTime !== null) return 1;
1561
+ if (leftTime !== null && rightTime === null) return -1;
1562
+ return compareText(left.name, right.name);
1563
+ });
1564
+ }
1565
+
1375
1566
  // src/FileExplorer/FileExplorer.tsx
1376
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1567
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1377
1568
  var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".txt", ".md", ".docx", ".pdf", ".dbk", ".zip"]);
1378
1569
  var INTERNAL_DRAG_TYPE = "application/x-docblocks-entry";
1379
1570
  var NEW_ITEM_ERROR_ID = "db-new-item-error";
@@ -1412,7 +1603,10 @@ function isInternalDrag(dataTransfer) {
1412
1603
  }
1413
1604
  function FileExplorer({
1414
1605
  provider,
1606
+ metadataRefreshKey,
1415
1607
  activeFilePath,
1608
+ sortMode,
1609
+ onSortModeChange,
1416
1610
  activeWorkspaceId,
1417
1611
  pinnedDocuments = [],
1418
1612
  pinnedPaths = [],
@@ -1430,7 +1624,7 @@ function FileExplorer({
1430
1624
  onMoveToWorkspace,
1431
1625
  className
1432
1626
  }) {
1433
- const tree = useFileTree(provider);
1627
+ const tree = useFileTree(provider, metadataRefreshKey, activeFilePath);
1434
1628
  const { childEntries, childIssues } = tree;
1435
1629
  const { reveal } = tree;
1436
1630
  const git = useGitContext();
@@ -1439,6 +1633,15 @@ function FileExplorer({
1439
1633
  [pinnedPaths]
1440
1634
  );
1441
1635
  const [newItemName, setNewItemName] = useState4("");
1636
+ const [uncontrolledSortMode, setUncontrolledSortMode] = useState4("name");
1637
+ const selectedSortMode = sortMode ?? uncontrolledSortMode;
1638
+ const selectSortMode = useCallback4(
1639
+ (mode) => {
1640
+ if (sortMode === void 0) setUncontrolledSortMode(mode);
1641
+ onSortModeChange?.(mode);
1642
+ },
1643
+ [onSortModeChange, sortMode]
1644
+ );
1442
1645
  const [newItemType, setNewItemType] = useState4(null);
1443
1646
  const [newItemCreationPending, setNewItemCreationPending] = useState4(false);
1444
1647
  const newItemCreationPendingRef = useRef4(false);
@@ -1549,6 +1752,7 @@ function FileExplorer({
1549
1752
  const filename = name.endsWith(".md") ? name : `${name}.md`;
1550
1753
  createdPath = `${prefix}${filename}`;
1551
1754
  await tree.createFile(createdPath, "");
1755
+ handleSelect(createdPath);
1552
1756
  } else if (itemType === "directory") {
1553
1757
  await tree.createDirectory(createdPath);
1554
1758
  }
@@ -1562,7 +1766,7 @@ function FileExplorer({
1562
1766
  setNewItemName("");
1563
1767
  setNewItemType(null);
1564
1768
  onTreeChange?.({ type: "create", path: createdPath });
1565
- }, [newItemName, newItemType, tree, onTreeChange]);
1769
+ }, [newItemName, newItemType, tree, handleSelect, onTreeChange]);
1566
1770
  const handleMoveToWorkspace = useCallback4(async () => {
1567
1771
  if (!onMoveToWorkspace || !moveDestinationId || movingToWorkspace) return;
1568
1772
  setMovingToWorkspace(true);
@@ -1700,14 +1904,18 @@ function FileExplorer({
1700
1904
  },
1701
1905
  [git]
1702
1906
  );
1907
+ const orderedVisibleEntries = useCallback4(
1908
+ (entries) => sortFileEntries(filterVisibleFileEntries(entries), selectedSortMode),
1909
+ [selectedSortMode]
1910
+ );
1703
1911
  const visibleRows = useMemo(
1704
1912
  () => flattenVisibleRows({
1705
- roots: tree.entries,
1706
- childrenOf: (dirPath) => getEquivalentPathValue(childEntries, dirPath) ?? [],
1913
+ roots: orderedVisibleEntries(tree.entries),
1914
+ childrenOf: (dirPath) => orderedVisibleEntries(getEquivalentPathValue(childEntries, dirPath) ?? []),
1707
1915
  isExpanded: (dirPath) => hasEquivalentPath2(tree.expanded, dirPath),
1708
- isVisible: (entry) => !isHiddenFileEntry(entry)
1916
+ isVisible: () => true
1709
1917
  }),
1710
- [tree.entries, tree.expanded, childEntries]
1918
+ [tree.entries, tree.expanded, childEntries, orderedVisibleEntries]
1711
1919
  );
1712
1920
  const selectedRowPath = useMemo(() => {
1713
1921
  if (!tree.selectedPath) return null;
@@ -1751,10 +1959,10 @@ function FileExplorer({
1751
1959
  );
1752
1960
  const renderEntries = useCallback4(
1753
1961
  (entries, depth) => {
1754
- const visible = filterVisibleFileEntries(entries);
1962
+ const visible = orderedVisibleEntries(entries);
1755
1963
  return visible.map((entry, index) => {
1756
1964
  const childIssue = entry.kind === "directory" ? getEquivalentPathValue(childIssues, entry.path) : void 0;
1757
- return /* @__PURE__ */ jsx4(
1965
+ return /* @__PURE__ */ jsx5(
1758
1966
  FileTreeNode,
1759
1967
  {
1760
1968
  entry,
@@ -1792,9 +2000,9 @@ function FileExplorer({
1792
2000
  role: "alert",
1793
2001
  "data-directory-path": childIssue.directoryPath,
1794
2002
  children: [
1795
- /* @__PURE__ */ jsx4("span", { children: childIssue.message }),
2003
+ /* @__PURE__ */ jsx5("span", { children: childIssue.message }),
1796
2004
  " ",
1797
- /* @__PURE__ */ jsx4(
2005
+ /* @__PURE__ */ jsx5(
1798
2006
  "button",
1799
2007
  {
1800
2008
  type: "button",
@@ -1829,7 +2037,8 @@ function FileExplorer({
1829
2037
  handleEntryDrop,
1830
2038
  activeRowPath,
1831
2039
  pinnedPathSet,
1832
- onTogglePin
2040
+ onTogglePin,
2041
+ orderedVisibleEntries
1833
2042
  ]
1834
2043
  );
1835
2044
  return /* @__PURE__ */ jsxs4(
@@ -1841,7 +2050,7 @@ function FileExplorer({
1841
2050
  onDragLeave: handleDragLeave,
1842
2051
  onDrop: handleDrop,
1843
2052
  children: [
1844
- onPinnedDocumentSelect && /* @__PURE__ */ jsx4(
2053
+ onPinnedDocumentSelect && /* @__PURE__ */ jsx5(
1845
2054
  PinnedDocuments,
1846
2055
  {
1847
2056
  documents: pinnedDocuments,
@@ -1854,11 +2063,39 @@ function FileExplorer({
1854
2063
  }
1855
2064
  ),
1856
2065
  /* @__PURE__ */ jsxs4("div", { className: "db-explorer-toolbar", children: [
1857
- /* @__PURE__ */ jsx4("span", { className: "db-explorer-title", children: "Files" }),
2066
+ /* @__PURE__ */ jsx5("span", { className: "db-explorer-title", children: "Files" }),
1858
2067
  /* @__PURE__ */ jsxs4("div", { className: "db-explorer-actions", children: [
1859
- /* @__PURE__ */ jsx4(
2068
+ /* @__PURE__ */ jsxs4("div", { className: "db-explorer-sort-actions", role: "group", "aria-label": "File sorting", children: [
2069
+ /* @__PURE__ */ jsx5(
2070
+ "button",
2071
+ {
2072
+ type: "button",
2073
+ className: "db-explorer-btn",
2074
+ onClick: () => selectSortMode("name"),
2075
+ title: "Sort by name",
2076
+ "aria-label": "Sort by name",
2077
+ "aria-pressed": selectedSortMode === "name",
2078
+ children: /* @__PURE__ */ jsx5(SortByNameIcon, {})
2079
+ }
2080
+ ),
2081
+ /* @__PURE__ */ jsx5(
2082
+ "button",
2083
+ {
2084
+ type: "button",
2085
+ className: "db-explorer-btn",
2086
+ onClick: () => selectSortMode("last-modified"),
2087
+ title: "Sort by last modified",
2088
+ "aria-label": "Sort by last modified",
2089
+ "aria-pressed": selectedSortMode === "last-modified",
2090
+ children: /* @__PURE__ */ jsx5(SortByLastModifiedIcon, {})
2091
+ }
2092
+ )
2093
+ ] }),
2094
+ /* @__PURE__ */ jsx5("span", { className: "db-explorer-action-divider", "aria-hidden": "true" }),
2095
+ /* @__PURE__ */ jsx5(
1860
2096
  "button",
1861
2097
  {
2098
+ type: "button",
1862
2099
  className: "db-explorer-btn",
1863
2100
  disabled: newItemCreationPending,
1864
2101
  onClick: () => {
@@ -1867,12 +2104,13 @@ function FileExplorer({
1867
2104
  },
1868
2105
  title: "New Folder",
1869
2106
  "aria-label": "New Folder",
1870
- children: /* @__PURE__ */ jsx4(NewFolderIcon, {})
2107
+ children: /* @__PURE__ */ jsx5(NewFolderIcon, {})
1871
2108
  }
1872
2109
  ),
1873
- /* @__PURE__ */ jsx4(
2110
+ /* @__PURE__ */ jsx5(
1874
2111
  "button",
1875
2112
  {
2113
+ type: "button",
1876
2114
  className: "db-explorer-btn",
1877
2115
  disabled: newItemCreationPending,
1878
2116
  onClick: () => {
@@ -1881,12 +2119,12 @@ function FileExplorer({
1881
2119
  },
1882
2120
  title: "New File",
1883
2121
  "aria-label": "New File",
1884
- children: /* @__PURE__ */ jsx4(NewFileIcon, {})
2122
+ children: /* @__PURE__ */ jsx5(NewFileIcon, {})
1885
2123
  }
1886
2124
  )
1887
2125
  ] })
1888
2126
  ] }),
1889
- onMoveToWorkspace && /* @__PURE__ */ jsx4("div", { className: "db-transient-move", children: !movePanelOpen ? /* @__PURE__ */ jsx4(
2127
+ onMoveToWorkspace && /* @__PURE__ */ jsx5("div", { className: "db-transient-move", children: !movePanelOpen ? /* @__PURE__ */ jsx5(
1890
2128
  "button",
1891
2129
  {
1892
2130
  type: "button",
@@ -1907,8 +2145,8 @@ function FileExplorer({
1907
2145
  void handleMoveToWorkspace();
1908
2146
  },
1909
2147
  children: [
1910
- /* @__PURE__ */ jsx4("label", { className: "db-transient-move-label", htmlFor: "db-transient-move-destination", children: "Move this document into" }),
1911
- /* @__PURE__ */ jsx4(
2148
+ /* @__PURE__ */ jsx5("label", { className: "db-transient-move-label", htmlFor: "db-transient-move-destination", children: "Move this document into" }),
2149
+ /* @__PURE__ */ jsx5(
1912
2150
  "select",
1913
2151
  {
1914
2152
  id: "db-transient-move-destination",
@@ -1919,13 +2157,13 @@ function FileExplorer({
1919
2157
  setMoveDestinationId(event.currentTarget.value);
1920
2158
  setMoveWorkspaceError(null);
1921
2159
  },
1922
- children: moveDestinations.map((destination) => /* @__PURE__ */ jsx4("option", { value: destination.id, children: destination.name }, destination.id))
2160
+ children: moveDestinations.map((destination) => /* @__PURE__ */ jsx5("option", { value: destination.id, children: destination.name }, destination.id))
1923
2161
  }
1924
2162
  ),
1925
- moveDestinations.length === 0 && /* @__PURE__ */ jsx4("p", { className: "db-transient-move-hint", children: "Open or create another workspace first." }),
1926
- moveWorkspaceError && /* @__PURE__ */ jsx4("div", { className: "db-transient-move-error", role: "alert", children: moveWorkspaceError }),
2163
+ moveDestinations.length === 0 && /* @__PURE__ */ jsx5("p", { className: "db-transient-move-hint", children: "Open or create another workspace first." }),
2164
+ moveWorkspaceError && /* @__PURE__ */ jsx5("div", { className: "db-transient-move-error", role: "alert", children: moveWorkspaceError }),
1927
2165
  /* @__PURE__ */ jsxs4("div", { className: "db-transient-move-actions", children: [
1928
- /* @__PURE__ */ jsx4(
2166
+ /* @__PURE__ */ jsx5(
1929
2167
  "button",
1930
2168
  {
1931
2169
  type: "button",
@@ -1938,7 +2176,7 @@ function FileExplorer({
1938
2176
  children: "Cancel"
1939
2177
  }
1940
2178
  ),
1941
- /* @__PURE__ */ jsx4(
2179
+ /* @__PURE__ */ jsx5(
1942
2180
  "button",
1943
2181
  {
1944
2182
  type: "submit",
@@ -1962,7 +2200,7 @@ function FileExplorer({
1962
2200
  void handleNewItemSubmit();
1963
2201
  },
1964
2202
  children: [
1965
- /* @__PURE__ */ jsx4(
2203
+ /* @__PURE__ */ jsx5(
1966
2204
  "input",
1967
2205
  {
1968
2206
  className: "db-new-item-input",
@@ -1986,14 +2224,14 @@ function FileExplorer({
1986
2224
  autoFocus: true
1987
2225
  }
1988
2226
  ),
1989
- newItemType === "file" && /* @__PURE__ */ jsx4("span", { className: "db-new-item-suffix", children: ".md" }),
1990
- /* @__PURE__ */ jsx4("button", { type: "submit", className: "db-new-item-add", disabled: newItemCreationPending, children: newItemCreationPending ? "Adding\u2026" : "Add" })
2227
+ newItemType === "file" && /* @__PURE__ */ jsx5("span", { className: "db-new-item-suffix", children: ".md" }),
2228
+ /* @__PURE__ */ jsx5("button", { type: "submit", className: "db-new-item-add", disabled: newItemCreationPending, children: newItemCreationPending ? "Adding\u2026" : "Add" })
1991
2229
  ]
1992
2230
  }
1993
2231
  ),
1994
- newItemError && /* @__PURE__ */ jsx4("div", { id: NEW_ITEM_ERROR_ID, className: "db-tree-error", role: "alert", children: newItemError })
2232
+ newItemError && /* @__PURE__ */ jsx5("div", { id: NEW_ITEM_ERROR_ID, className: "db-tree-error", role: "alert", children: newItemError })
1995
2233
  ] }),
1996
- moveError && /* @__PURE__ */ jsx4("div", { className: "db-tree-error", role: "alert", children: moveError }),
2234
+ moveError && /* @__PURE__ */ jsx5("div", { className: "db-tree-error", role: "alert", children: moveError }),
1997
2235
  tree.rootIssue && /* @__PURE__ */ jsxs4(
1998
2236
  "div",
1999
2237
  {
@@ -2001,9 +2239,9 @@ function FileExplorer({
2001
2239
  role: "alert",
2002
2240
  "data-directory-path": tree.rootIssue.directoryPath,
2003
2241
  children: [
2004
- /* @__PURE__ */ jsx4("span", { children: tree.rootIssue.message }),
2242
+ /* @__PURE__ */ jsx5("span", { children: tree.rootIssue.message }),
2005
2243
  " ",
2006
- /* @__PURE__ */ jsx4(
2244
+ /* @__PURE__ */ jsx5(
2007
2245
  "button",
2008
2246
  {
2009
2247
  type: "button",
@@ -2015,7 +2253,7 @@ function FileExplorer({
2015
2253
  ]
2016
2254
  }
2017
2255
  ),
2018
- tree.loading ? /* @__PURE__ */ jsx4("div", { className: "db-tree", role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsx4("div", { className: "db-tree-loading", children: "Loading..." }) }) : filterVisibleFileEntries(tree.entries).length === 0 ? /* @__PURE__ */ jsx4("div", { className: "db-tree", children: /* @__PURE__ */ jsx4("div", { className: "db-tree-empty", children: "No files yet" }) }) : /* @__PURE__ */ jsx4(
2256
+ tree.loading ? /* @__PURE__ */ jsx5("div", { className: "db-tree", role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsx5("div", { className: "db-tree-loading", children: "Loading..." }) }) : filterVisibleFileEntries(tree.entries).length === 0 ? /* @__PURE__ */ jsx5("div", { className: "db-tree", children: /* @__PURE__ */ jsx5("div", { className: "db-tree-empty", children: "No files yet" }) }) : /* @__PURE__ */ jsx5(
2019
2257
  "div",
2020
2258
  {
2021
2259
  ref: treeRef,
@@ -2037,14 +2275,14 @@ function FileExplorer({
2037
2275
  import { Fragment as Fragment2, useState as useState5, useEffect as useEffect5, useCallback as useCallback5, useRef as useRef5 } from "react";
2038
2276
  import { listWorkspaces, saveWorkspace, touchWorkspace } from "@bendyline/docblocks/workspace";
2039
2277
  import { isElectronHost } from "@bendyline/docblocks/host";
2040
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2278
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
2041
2279
  function isNativeFileSystemSupported() {
2042
2280
  return typeof globalThis !== "undefined" && typeof globalThis.showDirectoryPicker === "function";
2043
2281
  }
2044
2282
  function WorkspacePath({ path }) {
2045
2283
  return path.split(/([\\/])/).map((segment, index) => /* @__PURE__ */ jsxs5(Fragment2, { children: [
2046
2284
  segment,
2047
- (segment === "\\" || segment === "/") && /* @__PURE__ */ jsx5("wbr", {})
2285
+ (segment === "\\" || segment === "/") && /* @__PURE__ */ jsx6("wbr", {})
2048
2286
  ] }, index));
2049
2287
  }
2050
2288
  function WorkspacePicker({
@@ -2173,9 +2411,9 @@ function WorkspacePicker({
2173
2411
  "aria-label": `Switch workspace, current: ${activeWorkspaceName}`,
2174
2412
  "aria-expanded": isOpen,
2175
2413
  children: [
2176
- /* @__PURE__ */ jsx5("span", { className: "db-workspace-picker-label", children: activeWorkspaceName }),
2177
- /* @__PURE__ */ jsx5("span", { className: "db-workspace-picker-compact-icon", children: /* @__PURE__ */ jsx5(FolderIcon, {}) }),
2178
- /* @__PURE__ */ jsx5(
2414
+ /* @__PURE__ */ jsx6("span", { className: "db-workspace-picker-label", children: activeWorkspaceName }),
2415
+ /* @__PURE__ */ jsx6("span", { className: "db-workspace-picker-compact-icon", children: /* @__PURE__ */ jsx6(FolderIcon, {}) }),
2416
+ /* @__PURE__ */ jsx6(
2179
2417
  "span",
2180
2418
  {
2181
2419
  className: `db-workspace-picker-caret${isOpen ? " db-workspace-picker-caret--open" : ""}`,
@@ -2186,22 +2424,22 @@ function WorkspacePicker({
2186
2424
  }
2187
2425
  ),
2188
2426
  isOpen && /* @__PURE__ */ jsxs5("div", { className: "db-workspace-dropdown", children: [
2189
- workspaces.map((ws) => /* @__PURE__ */ jsx5(
2427
+ workspaces.map((ws) => /* @__PURE__ */ jsx6(
2190
2428
  "button",
2191
2429
  {
2192
2430
  className: `db-workspace-dropdown-item ${ws.id === activeWorkspaceId ? "db-workspace-dropdown-item--active" : ""}`,
2193
2431
  onClick: () => handleSelect(ws),
2194
2432
  children: /* @__PURE__ */ jsxs5("span", { className: "db-workspace-details", children: [
2195
2433
  /* @__PURE__ */ jsxs5("span", { className: "db-workspace-heading", children: [
2196
- /* @__PURE__ */ jsx5("span", { children: ws.name }),
2197
- (ws.type === "native" || ws.type === "electron-native") && /* @__PURE__ */ jsx5("span", { className: "db-workspace-type", children: "(folder)" })
2434
+ /* @__PURE__ */ jsx6("span", { children: ws.name }),
2435
+ (ws.type === "native" || ws.type === "electron-native") && /* @__PURE__ */ jsx6("span", { className: "db-workspace-type", children: "(folder)" })
2198
2436
  ] }),
2199
- ws.rootPath && /* @__PURE__ */ jsx5("span", { className: "db-workspace-path", title: ws.rootPath, children: /* @__PURE__ */ jsx5(WorkspacePath, { path: ws.rootPath }) })
2437
+ ws.rootPath && /* @__PURE__ */ jsx6("span", { className: "db-workspace-path", title: ws.rootPath, children: /* @__PURE__ */ jsx6(WorkspacePath, { path: ws.rootPath }) })
2200
2438
  ] })
2201
2439
  },
2202
2440
  ws.id
2203
2441
  )),
2204
- /* @__PURE__ */ jsx5("div", { className: "db-workspace-dropdown-divider" }),
2442
+ /* @__PURE__ */ jsx6("div", { className: "db-workspace-dropdown-divider" }),
2205
2443
  !electron && (creatingNew ? /* @__PURE__ */ jsxs5(
2206
2444
  "form",
2207
2445
  {
@@ -2212,8 +2450,8 @@ function WorkspacePicker({
2212
2450
  void handleCreateNew();
2213
2451
  },
2214
2452
  children: [
2215
- /* @__PURE__ */ jsx5("label", { className: "db-workspace-create-label", htmlFor: "db-new-workspace-name", children: "Workspace name" }),
2216
- /* @__PURE__ */ jsx5(
2453
+ /* @__PURE__ */ jsx6("label", { className: "db-workspace-create-label", htmlFor: "db-new-workspace-name", children: "Workspace name" }),
2454
+ /* @__PURE__ */ jsx6(
2217
2455
  "input",
2218
2456
  {
2219
2457
  id: "db-new-workspace-name",
@@ -2233,9 +2471,9 @@ function WorkspacePicker({
2233
2471
  }
2234
2472
  }
2235
2473
  ),
2236
- newWorkspaceError && /* @__PURE__ */ jsx5("p", { id: "db-new-workspace-error", className: "db-workspace-create-error", role: "alert", children: newWorkspaceError }),
2474
+ newWorkspaceError && /* @__PURE__ */ jsx6("p", { id: "db-new-workspace-error", className: "db-workspace-create-error", role: "alert", children: newWorkspaceError }),
2237
2475
  /* @__PURE__ */ jsxs5("div", { className: "db-workspace-create-actions", children: [
2238
- /* @__PURE__ */ jsx5(
2476
+ /* @__PURE__ */ jsx6(
2239
2477
  "button",
2240
2478
  {
2241
2479
  type: "button",
@@ -2245,15 +2483,15 @@ function WorkspacePicker({
2245
2483
  children: "Cancel"
2246
2484
  }
2247
2485
  ),
2248
- /* @__PURE__ */ jsx5("button", { type: "submit", disabled: newWorkspacePending, children: newWorkspacePending ? "Creating\xE2\u20AC\xA6" : "Create" })
2486
+ /* @__PURE__ */ jsx6("button", { type: "submit", disabled: newWorkspacePending, children: newWorkspacePending ? "Creating\xE2\u20AC\xA6" : "Create" })
2249
2487
  ] })
2250
2488
  ]
2251
2489
  }
2252
- ) : /* @__PURE__ */ jsx5("button", { className: "db-workspace-dropdown-item", onClick: handleStartCreateNew, children: /* @__PURE__ */ jsxs5("span", { className: "db-workspace-dropdown-action-label", children: [
2253
- /* @__PURE__ */ jsx5(NewFolderIcon, {}),
2254
- /* @__PURE__ */ jsx5("span", { children: "New Workspace" })
2490
+ ) : /* @__PURE__ */ jsx6("button", { className: "db-workspace-dropdown-item", onClick: handleStartCreateNew, children: /* @__PURE__ */ jsxs5("span", { className: "db-workspace-dropdown-action-label", children: [
2491
+ /* @__PURE__ */ jsx6(NewFolderIcon, {}),
2492
+ /* @__PURE__ */ jsx6("span", { children: "New Workspace" })
2255
2493
  ] }) })),
2256
- (electron || isNativeFileSystemSupported()) && /* @__PURE__ */ jsx5(
2494
+ (electron || isNativeFileSystemSupported()) && /* @__PURE__ */ jsx6(
2257
2495
  "button",
2258
2496
  {
2259
2497
  className: "db-workspace-dropdown-item",
@@ -2264,7 +2502,7 @@ function WorkspacePicker({
2264
2502
  children: "Open Folder..."
2265
2503
  }
2266
2504
  ),
2267
- onCloneRepository && /* @__PURE__ */ jsx5(
2505
+ onCloneRepository && /* @__PURE__ */ jsx6(
2268
2506
  "button",
2269
2507
  {
2270
2508
  className: "db-workspace-dropdown-item",
@@ -2320,7 +2558,7 @@ import {
2320
2558
  // src/AppMenu/AppMenu.tsx
2321
2559
  import { useState as useState6, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect6 } from "react";
2322
2560
  import { isElectronHost as isElectronHost2 } from "@bendyline/docblocks/host";
2323
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2561
+ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
2324
2562
  function formatBytes(bytes) {
2325
2563
  if (!Number.isFinite(bytes) || bytes < 0) return "\u2014";
2326
2564
  let value = bytes;
@@ -2409,7 +2647,7 @@ function AppMenu({
2409
2647
  "aria-expanded": isOpen,
2410
2648
  "aria-haspopup": "menu",
2411
2649
  children: [
2412
- logoUrl ? /* @__PURE__ */ jsx6(
2650
+ logoUrl ? /* @__PURE__ */ jsx7(
2413
2651
  "img",
2414
2652
  {
2415
2653
  src: logoUrl,
@@ -2418,8 +2656,8 @@ function AppMenu({
2418
2656
  width: 1266,
2419
2657
  height: 544
2420
2658
  }
2421
- ) : /* @__PURE__ */ jsx6("span", { className: "db-app-menu-label", children: "docblocks" }),
2422
- /* @__PURE__ */ jsx6(
2659
+ ) : /* @__PURE__ */ jsx7("span", { className: "db-app-menu-label", children: "docblocks" }),
2660
+ /* @__PURE__ */ jsx7(
2423
2661
  "span",
2424
2662
  {
2425
2663
  className: `db-app-menu-caret${isOpen ? " db-app-menu-caret--open" : ""}`,
@@ -2437,7 +2675,7 @@ function AppMenu({
2437
2675
  role: "menu",
2438
2676
  onKeyDown: handleMenuKeyDown,
2439
2677
  children: [
2440
- /* @__PURE__ */ jsx6(
2678
+ /* @__PURE__ */ jsx7(
2441
2679
  "button",
2442
2680
  {
2443
2681
  className: "db-app-menu-item",
@@ -2447,7 +2685,7 @@ function AppMenu({
2447
2685
  children: "Settings"
2448
2686
  }
2449
2687
  ),
2450
- onInstallApp && /* @__PURE__ */ jsx6(
2688
+ onInstallApp && /* @__PURE__ */ jsx7(
2451
2689
  "button",
2452
2690
  {
2453
2691
  className: "db-app-menu-item",
@@ -2457,7 +2695,7 @@ function AppMenu({
2457
2695
  children: "Install DocBlocks\u2026"
2458
2696
  }
2459
2697
  ),
2460
- onKeepBrowserData && /* @__PURE__ */ jsx6(
2698
+ onKeepBrowserData && /* @__PURE__ */ jsx7(
2461
2699
  "button",
2462
2700
  {
2463
2701
  className: "db-app-menu-item",
@@ -2467,7 +2705,7 @@ function AppMenu({
2467
2705
  children: "Protect data from browser cleanup"
2468
2706
  }
2469
2707
  ),
2470
- onDownloadAllWorkspaces && /* @__PURE__ */ jsx6(
2708
+ onDownloadAllWorkspaces && /* @__PURE__ */ jsx7(
2471
2709
  "button",
2472
2710
  {
2473
2711
  className: "db-app-menu-item",
@@ -2477,8 +2715,8 @@ function AppMenu({
2477
2715
  children: "Download all workspaces"
2478
2716
  }
2479
2717
  ),
2480
- /* @__PURE__ */ jsx6("div", { className: "db-app-menu-divider" }),
2481
- /* @__PURE__ */ jsx6(
2718
+ /* @__PURE__ */ jsx7("div", { className: "db-app-menu-divider" }),
2719
+ /* @__PURE__ */ jsx7(
2482
2720
  "button",
2483
2721
  {
2484
2722
  className: "db-app-menu-item",
@@ -2493,21 +2731,21 @@ function AppMenu({
2493
2731
  )
2494
2732
  ] }),
2495
2733
  showSettings && /* @__PURE__ */ jsxs6(SettingsDialog, { onClose: () => setShowSettings(false), children: [
2496
- /* @__PURE__ */ jsx6(
2734
+ /* @__PURE__ */ jsx7(
2497
2735
  ThemeSettings,
2498
2736
  {
2499
2737
  value: themePreference,
2500
2738
  onChange: (preference) => onThemeChange?.(preference)
2501
2739
  }
2502
2740
  ),
2503
- /* @__PURE__ */ jsx6(
2741
+ /* @__PURE__ */ jsx7(
2504
2742
  AccentColorSettings,
2505
2743
  {
2506
2744
  value: accentColor,
2507
2745
  onChange: (color) => onAccentColorChange?.(color)
2508
2746
  }
2509
2747
  ),
2510
- /* @__PURE__ */ jsx6(
2748
+ /* @__PURE__ */ jsx7(
2511
2749
  WriteCanvasSettingsControls,
2512
2750
  {
2513
2751
  value: writeCanvasSettings,
@@ -2515,14 +2753,14 @@ function AppMenu({
2515
2753
  }
2516
2754
  ),
2517
2755
  getStorageEstimate && /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
2518
- /* @__PURE__ */ jsx6("legend", { className: "db-settings-legend", children: "Storage" }),
2519
- /* @__PURE__ */ jsx6("p", { className: "db-settings-hint", children: storageEstimate ? `DocBlocks documents and app data are using ${formatBytes(
2756
+ /* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: "Storage" }),
2757
+ /* @__PURE__ */ jsx7("p", { className: "db-settings-hint", children: storageEstimate ? `DocBlocks documents and app data are using ${formatBytes(
2520
2758
  storageEstimate.usage
2521
2759
  )} of the ${formatBytes(
2522
2760
  storageEstimate.quota
2523
2761
  )} this browser allows for the site.` : "Storage usage is not available in this browser." }),
2524
- storagePersistent !== void 0 && /* @__PURE__ */ jsx6("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." }),
2525
- onKeepBrowserData && /* @__PURE__ */ jsx6(
2762
+ storagePersistent !== void 0 && /* @__PURE__ */ jsx7("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." }),
2763
+ onKeepBrowserData && /* @__PURE__ */ jsx7(
2526
2764
  "button",
2527
2765
  {
2528
2766
  type: "button",
@@ -2534,15 +2772,15 @@ function AppMenu({
2534
2772
  )
2535
2773
  ] }),
2536
2774
  onVersioningPreferenceChange && /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
2537
- /* @__PURE__ */ jsx6("legend", { className: "db-settings-legend", children: "Version history" }),
2775
+ /* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: "Version history" }),
2538
2776
  /* @__PURE__ */ jsxs6("p", { className: "db-settings-hint", children: [
2539
2777
  "When on, DocBlocks keeps prior revisions of each document inside a sibling",
2540
2778
  " ",
2541
- /* @__PURE__ */ jsx6("code", { children: "<name>_files/.versions/" }),
2779
+ /* @__PURE__ */ jsx7("code", { children: "<name>_files/.versions/" }),
2542
2780
  " folder. Individual workspaces can override this default in their own settings."
2543
2781
  ] }),
2544
2782
  /* @__PURE__ */ jsxs6("label", { className: "db-settings-radio", children: [
2545
- /* @__PURE__ */ jsx6(
2783
+ /* @__PURE__ */ jsx7(
2546
2784
  "input",
2547
2785
  {
2548
2786
  type: "radio",
@@ -2555,7 +2793,7 @@ function AppMenu({
2555
2793
  "On for all workspaces"
2556
2794
  ] }),
2557
2795
  /* @__PURE__ */ jsxs6("label", { className: "db-settings-radio", children: [
2558
- /* @__PURE__ */ jsx6(
2796
+ /* @__PURE__ */ jsx7(
2559
2797
  "input",
2560
2798
  {
2561
2799
  type: "radio",
@@ -2568,7 +2806,7 @@ function AppMenu({
2568
2806
  "On in browser workspaces, off for local folders"
2569
2807
  ] }),
2570
2808
  /* @__PURE__ */ jsxs6("label", { className: "db-settings-radio", children: [
2571
- /* @__PURE__ */ jsx6(
2809
+ /* @__PURE__ */ jsx7(
2572
2810
  "input",
2573
2811
  {
2574
2812
  type: "radio",
@@ -2584,14 +2822,14 @@ function AppMenu({
2584
2822
  ] }),
2585
2823
  showAbout && /* @__PURE__ */ jsxs6(Dialog, { title: "About DocBlocks", onClose: () => setShowAbout(false), children: [
2586
2824
  /* @__PURE__ */ jsxs6("p", { children: [
2587
- /* @__PURE__ */ jsx6("strong", { children: "DocBlocks" }),
2825
+ /* @__PURE__ */ jsx7("strong", { children: "DocBlocks" }),
2588
2826
  " is a local-first Markdown document editor. Your files stay under your control."
2589
2827
  ] }),
2590
2828
  /* @__PURE__ */ jsxs6("aside", { className: "db-about-beta", children: [
2591
- /* @__PURE__ */ jsx6("strong", { children: "Beta Software." }),
2829
+ /* @__PURE__ */ jsx7("strong", { children: "Beta Software." }),
2592
2830
  " We're still working through initial hiccups and issues. Please bear with us, make sure you keep backups, and",
2593
2831
  " ",
2594
- /* @__PURE__ */ jsx6(
2832
+ /* @__PURE__ */ jsx7(
2595
2833
  "a",
2596
2834
  {
2597
2835
  href: "https://github.com/bendyline/docblocks/issues/new",
@@ -2604,27 +2842,27 @@ function AppMenu({
2604
2842
  "where you find them. Thanks!"
2605
2843
  ] }),
2606
2844
  appVersion && /* @__PURE__ */ jsxs6("p", { className: "db-about-version", children: [
2607
- /* @__PURE__ */ jsx6("span", { children: "Version" }),
2608
- /* @__PURE__ */ jsx6("code", { "aria-label": `DocBlocks version ${appVersion}`, children: appVersion })
2845
+ /* @__PURE__ */ jsx7("span", { children: "Version" }),
2846
+ /* @__PURE__ */ jsx7("code", { "aria-label": `DocBlocks version ${appVersion}`, children: appVersion })
2609
2847
  ] }),
2610
2848
  appBuildDate && /* @__PURE__ */ jsxs6("p", { className: "db-about-version", children: [
2611
- /* @__PURE__ */ jsx6("span", { children: "Build" }),
2612
- /* @__PURE__ */ jsx6("time", { dateTime: appBuildDate, children: appBuildDate })
2849
+ /* @__PURE__ */ jsx7("span", { children: "Build" }),
2850
+ /* @__PURE__ */ jsx7("time", { dateTime: appBuildDate, children: appBuildDate })
2613
2851
  ] }),
2614
2852
  /* @__PURE__ */ jsxs6("p", { children: [
2615
2853
  "Built with",
2616
2854
  " ",
2617
- /* @__PURE__ */ jsx6("a", { href: "https://github.com/bendyline/squisq", target: "_blank", rel: "noopener noreferrer", children: "squisq" }),
2855
+ /* @__PURE__ */ jsx7("a", { href: "https://github.com/bendyline/squisq", target: "_blank", rel: "noopener noreferrer", children: "squisq" }),
2618
2856
  " ",
2619
2857
  "by",
2620
2858
  " ",
2621
- /* @__PURE__ */ jsx6("a", { href: "https://bendyline.com", target: "_blank", rel: "noopener noreferrer", children: "Bendyline" }),
2859
+ /* @__PURE__ */ jsx7("a", { href: "https://bendyline.com", target: "_blank", rel: "noopener noreferrer", children: "Bendyline" }),
2622
2860
  "."
2623
2861
  ] }),
2624
2862
  /* @__PURE__ */ jsxs6("p", { className: "db-dialog-links", children: [
2625
- /* @__PURE__ */ jsx6("a", { href: moreInformationUrl, target: "_blank", rel: "noopener noreferrer", children: "More information..." }),
2626
- /* @__PURE__ */ jsx6("span", { className: "db-dialog-sep", children: "\xB7" }),
2627
- /* @__PURE__ */ jsx6(
2863
+ /* @__PURE__ */ jsx7("a", { href: moreInformationUrl, target: "_blank", rel: "noopener noreferrer", children: "More information..." }),
2864
+ /* @__PURE__ */ jsx7("span", { className: "db-dialog-sep", children: "\xB7" }),
2865
+ /* @__PURE__ */ jsx7(
2628
2866
  "a",
2629
2867
  {
2630
2868
  href: "https://github.com/bendyline/docblocks",
@@ -2633,8 +2871,8 @@ function AppMenu({
2633
2871
  children: "GitHub"
2634
2872
  }
2635
2873
  ),
2636
- /* @__PURE__ */ jsx6("span", { className: "db-dialog-sep", children: "\xB7" }),
2637
- /* @__PURE__ */ jsx6(
2874
+ /* @__PURE__ */ jsx7("span", { className: "db-dialog-sep", children: "\xB7" }),
2875
+ /* @__PURE__ */ jsx7(
2638
2876
  "a",
2639
2877
  {
2640
2878
  href: "https://github.com/bendyline/docblocks/releases",
@@ -2643,8 +2881,8 @@ function AppMenu({
2643
2881
  children: "Release notes"
2644
2882
  }
2645
2883
  ),
2646
- /* @__PURE__ */ jsx6("span", { className: "db-dialog-sep", children: "\xB7" }),
2647
- /* @__PURE__ */ jsx6(
2884
+ /* @__PURE__ */ jsx7("span", { className: "db-dialog-sep", children: "\xB7" }),
2885
+ /* @__PURE__ */ jsx7(
2648
2886
  "a",
2649
2887
  {
2650
2888
  href: "https://github.com/bendyline/docblocks/issues",
@@ -2653,8 +2891,8 @@ function AppMenu({
2653
2891
  children: "Support"
2654
2892
  }
2655
2893
  ),
2656
- /* @__PURE__ */ jsx6("span", { className: "db-dialog-sep", children: "\xB7" }),
2657
- /* @__PURE__ */ jsx6(
2894
+ /* @__PURE__ */ jsx7("span", { className: "db-dialog-sep", children: "\xB7" }),
2895
+ /* @__PURE__ */ jsx7(
2658
2896
  "a",
2659
2897
  {
2660
2898
  href: "https://github.com/bendyline/docblocks/blob/main/LICENSE",
@@ -2663,8 +2901,8 @@ function AppMenu({
2663
2901
  children: "License (MIT)"
2664
2902
  }
2665
2903
  ),
2666
- /* @__PURE__ */ jsx6("span", { className: "db-dialog-sep", children: "\xB7" }),
2667
- /* @__PURE__ */ jsx6(
2904
+ /* @__PURE__ */ jsx7("span", { className: "db-dialog-sep", children: "\xB7" }),
2905
+ /* @__PURE__ */ jsx7(
2668
2906
  "a",
2669
2907
  {
2670
2908
  href: "https://github.com/bendyline/docblocks/blob/main/NOTICE.md",
@@ -2680,7 +2918,7 @@ function AppMenu({
2680
2918
 
2681
2919
  // src/WorkspacePicker/WorkspaceSettingsButton.tsx
2682
2920
  import { useState as useState7, useCallback as useCallback7, useRef as useRef7, useEffect as useEffect7 } from "react";
2683
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2921
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2684
2922
  function WorkspaceSettingsButton({
2685
2923
  onSettings,
2686
2924
  onRename,
@@ -2708,7 +2946,7 @@ function WorkspaceSettingsButton({
2708
2946
  [closeMenu]
2709
2947
  );
2710
2948
  return /* @__PURE__ */ jsxs7("div", { ref: containerRef, className: "db-ws-settings", children: [
2711
- /* @__PURE__ */ jsx7(
2949
+ /* @__PURE__ */ jsx8(
2712
2950
  "button",
2713
2951
  {
2714
2952
  ref: triggerRef,
@@ -2719,7 +2957,7 @@ function WorkspaceSettingsButton({
2719
2957
  "aria-haspopup": "menu",
2720
2958
  "aria-label": "Workspace settings",
2721
2959
  title: "Workspace settings",
2722
- children: /* @__PURE__ */ jsx7(WorkspaceIcon, {})
2960
+ children: /* @__PURE__ */ jsx8(WorkspaceIcon, {})
2723
2961
  }
2724
2962
  ),
2725
2963
  isOpen && /* @__PURE__ */ jsxs7(
@@ -2730,7 +2968,7 @@ function WorkspaceSettingsButton({
2730
2968
  role: "menu",
2731
2969
  onKeyDown: handleMenuKeyDown,
2732
2970
  children: [
2733
- /* @__PURE__ */ jsx7(
2971
+ /* @__PURE__ */ jsx8(
2734
2972
  "button",
2735
2973
  {
2736
2974
  className: "db-ws-settings-item",
@@ -2740,7 +2978,7 @@ function WorkspaceSettingsButton({
2740
2978
  children: "Workspace settings\u2026"
2741
2979
  }
2742
2980
  ),
2743
- /* @__PURE__ */ jsx7(
2981
+ /* @__PURE__ */ jsx8(
2744
2982
  "button",
2745
2983
  {
2746
2984
  className: "db-ws-settings-item",
@@ -2750,7 +2988,7 @@ function WorkspaceSettingsButton({
2750
2988
  children: "Rename workspace"
2751
2989
  }
2752
2990
  ),
2753
- /* @__PURE__ */ jsx7(
2991
+ /* @__PURE__ */ jsx8(
2754
2992
  "button",
2755
2993
  {
2756
2994
  className: "db-ws-settings-item",
@@ -2760,8 +2998,8 @@ function WorkspaceSettingsButton({
2760
2998
  children: "Download workspace"
2761
2999
  }
2762
3000
  ),
2763
- /* @__PURE__ */ jsx7("div", { className: "db-ws-settings-divider" }),
2764
- /* @__PURE__ */ jsx7(
3001
+ /* @__PURE__ */ jsx8("div", { className: "db-ws-settings-divider" }),
3002
+ /* @__PURE__ */ jsx8(
2765
3003
  "button",
2766
3004
  {
2767
3005
  className: "db-ws-settings-item db-ws-settings-item--danger",
@@ -2813,7 +3051,7 @@ function resolveVersioningEnabled(workspace, globalPref) {
2813
3051
  }
2814
3052
 
2815
3053
  // src/WorkspacePicker/WorkspaceSettingsDialog.tsx
2816
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
3054
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2817
3055
  var VERSIONING_LABELS = {
2818
3056
  on: "on",
2819
3057
  "browser-only": "on for browser workspaces, off for local folders",
@@ -2834,21 +3072,21 @@ function WorkspaceSettingsDialog({
2834
3072
  const inheritLabel = `Inherit default \u2014 currently ${VERSIONING_LABELS[globalVersioningPreference]} (${inheritedEnabled ? "on" : "off"} for this workspace)`;
2835
3073
  return /* @__PURE__ */ jsxs8(Dialog, { title: "Workspace settings", onClose, children: [
2836
3074
  /* @__PURE__ */ jsxs8("p", { className: "db-settings-hint", children: [
2837
- /* @__PURE__ */ jsx8("strong", { children: workspace.name }),
3075
+ /* @__PURE__ */ jsx9("strong", { children: workspace.name }),
2838
3076
  " \xB7",
2839
3077
  " ",
2840
3078
  isLocal ? "Local folder workspace" : "Browser workspace"
2841
3079
  ] }),
2842
3080
  /* @__PURE__ */ jsxs8("fieldset", { className: "db-settings-fieldset", children: [
2843
- /* @__PURE__ */ jsx8("legend", { className: "db-settings-legend", children: "Version history" }),
3081
+ /* @__PURE__ */ jsx9("legend", { className: "db-settings-legend", children: "Version history" }),
2844
3082
  /* @__PURE__ */ jsxs8("p", { className: "db-settings-hint", children: [
2845
3083
  "Controls whether DocBlocks keeps prior revisions in",
2846
3084
  " ",
2847
- /* @__PURE__ */ jsx8("code", { children: "<name>_files/.versions/" }),
3085
+ /* @__PURE__ */ jsx9("code", { children: "<name>_files/.versions/" }),
2848
3086
  " for documents in this workspace."
2849
3087
  ] }),
2850
3088
  /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
2851
- /* @__PURE__ */ jsx8(
3089
+ /* @__PURE__ */ jsx9(
2852
3090
  "input",
2853
3091
  {
2854
3092
  type: "radio",
@@ -2861,7 +3099,7 @@ function WorkspaceSettingsDialog({
2861
3099
  inheritLabel
2862
3100
  ] }),
2863
3101
  /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
2864
- /* @__PURE__ */ jsx8(
3102
+ /* @__PURE__ */ jsx9(
2865
3103
  "input",
2866
3104
  {
2867
3105
  type: "radio",
@@ -2874,7 +3112,7 @@ function WorkspaceSettingsDialog({
2874
3112
  "On for this workspace"
2875
3113
  ] }),
2876
3114
  /* @__PURE__ */ jsxs8("label", { className: "db-settings-radio", children: [
2877
- /* @__PURE__ */ jsx8(
3115
+ /* @__PURE__ */ jsx9(
2878
3116
  "input",
2879
3117
  {
2880
3118
  type: "radio",
@@ -2891,7 +3129,7 @@ function WorkspaceSettingsDialog({
2891
3129
  }
2892
3130
 
2893
3131
  // src/hooks/useDocumentSession.ts
2894
- import { useState as useState8, useSyncExternalStore } from "react";
3132
+ import { useState as useState8, useSyncExternalStore as useSyncExternalStore2 } from "react";
2895
3133
  import {
2896
3134
  DocumentRecoveryJournal,
2897
3135
  DocumentSession,
@@ -2904,7 +3142,7 @@ function useDocumentSession(autoSaveDelayMs = 500) {
2904
3142
  recoveryJournal: new DocumentRecoveryJournal(getDefaultDocumentRecoveryStorage())
2905
3143
  })
2906
3144
  );
2907
- const snapshot = useSyncExternalStore(
3145
+ const snapshot = useSyncExternalStore2(
2908
3146
  session.subscribe,
2909
3147
  session.getSnapshot,
2910
3148
  session.getSnapshot
@@ -2914,14 +3152,14 @@ function useDocumentSession(autoSaveDelayMs = 500) {
2914
3152
 
2915
3153
  // src/Export/DeferredExportToolbarControls.tsx
2916
3154
  import { lazy, Suspense } from "react";
2917
- import { jsx as jsx9 } from "react/jsx-runtime";
3155
+ import { jsx as jsx10 } from "react/jsx-runtime";
2918
3156
  var ExportToolbarControlsImplementation = lazy(
2919
- () => import("./ExportToolbarControls-773QRE4R.js").then((module) => ({
3157
+ () => import("./ExportToolbarControls-I2EX7ZTH.js").then((module) => ({
2920
3158
  default: module.ExportToolbarControls
2921
3159
  }))
2922
3160
  );
2923
3161
  function ExportToolbarControls(props) {
2924
- return /* @__PURE__ */ jsx9(Suspense, { fallback: null, children: /* @__PURE__ */ jsx9(ExportToolbarControlsImplementation, { ...props }) });
3162
+ return /* @__PURE__ */ jsx10(Suspense, { fallback: null, children: /* @__PURE__ */ jsx10(ExportToolbarControlsImplementation, { ...props }) });
2925
3163
  }
2926
3164
 
2927
3165
  // src/Git/useGit.ts
@@ -3586,7 +3824,7 @@ import React2, { useCallback as useCallback11, useEffect as useEffect12, useRef
3586
3824
 
3587
3825
  // src/components/PromptDialog.tsx
3588
3826
  import { useCallback as useCallback10, useEffect as useEffect11, useId as useId2, useRef as useRef10, useState as useState11 } from "react";
3589
- import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
3827
+ import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
3590
3828
  function PromptDialog({ request, onSettle }) {
3591
3829
  const [value, setValue] = useState11(request.initialValue ?? "");
3592
3830
  const inputRef = useRef10(null);
@@ -3599,7 +3837,7 @@ function PromptDialog({ request, onSettle }) {
3599
3837
  useEffect11(() => {
3600
3838
  inputRef.current?.select();
3601
3839
  }, []);
3602
- return /* @__PURE__ */ jsx10(
3840
+ return /* @__PURE__ */ jsx11(
3603
3841
  Dialog,
3604
3842
  {
3605
3843
  title: request.title,
@@ -3607,8 +3845,8 @@ function PromptDialog({ request, onSettle }) {
3607
3845
  initialFocusRef: inputRef,
3608
3846
  closeOnBackdrop: false,
3609
3847
  footer: /* @__PURE__ */ jsxs9(Fragment4, { children: [
3610
- /* @__PURE__ */ jsx10("button", { type: "button", className: "db-git-secondary-btn", onClick: cancel, children: "Cancel" }),
3611
- /* @__PURE__ */ jsx10(
3848
+ /* @__PURE__ */ jsx11("button", { type: "button", className: "db-git-secondary-btn", onClick: cancel, children: "Cancel" }),
3849
+ /* @__PURE__ */ jsx11(
3612
3850
  "button",
3613
3851
  {
3614
3852
  type: "button",
@@ -3620,8 +3858,8 @@ function PromptDialog({ request, onSettle }) {
3620
3858
  )
3621
3859
  ] }),
3622
3860
  children: /* @__PURE__ */ jsxs9("div", { className: "db-git-form-row", children: [
3623
- /* @__PURE__ */ jsx10("label", { className: "db-git-form-label", htmlFor: inputId, children: request.label }),
3624
- /* @__PURE__ */ jsx10(
3861
+ /* @__PURE__ */ jsx11("label", { className: "db-git-form-label", htmlFor: inputId, children: request.label }),
3862
+ /* @__PURE__ */ jsx11(
3625
3863
  "input",
3626
3864
  {
3627
3865
  id: inputId,
@@ -3680,7 +3918,7 @@ import React4, { useCallback as useCallback13, useEffect as useEffect13, useRef
3680
3918
 
3681
3919
  // src/components/ConfirmDialog.tsx
3682
3920
  import { useCallback as useCallback12, useRef as useRef12 } from "react";
3683
- import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
3921
+ import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
3684
3922
  function ConfirmDialog({ request, onSettle }) {
3685
3923
  const acknowledge = request.kind === "acknowledge";
3686
3924
  const destructive = request.kind === "confirm" && request.destructive === true;
@@ -3689,15 +3927,15 @@ function ConfirmDialog({ request, onSettle }) {
3689
3927
  const accept = useCallback12(() => onSettle(true), [onSettle]);
3690
3928
  const reject = useCallback12(() => onSettle(false), [onSettle]);
3691
3929
  const close = acknowledge ? accept : reject;
3692
- return /* @__PURE__ */ jsx11(
3930
+ return /* @__PURE__ */ jsx12(
3693
3931
  Dialog,
3694
3932
  {
3695
3933
  title: request.title,
3696
3934
  onClose: close,
3697
3935
  initialFocusRef: destructive ? cancelRef : confirmRef,
3698
3936
  footer: /* @__PURE__ */ jsxs10(Fragment5, { children: [
3699
- !acknowledge && /* @__PURE__ */ jsx11("button", { ref: cancelRef, type: "button", className: "db-git-secondary-btn", onClick: reject, children: request.cancelLabel ?? "Cancel" }),
3700
- /* @__PURE__ */ jsx11(
3937
+ !acknowledge && /* @__PURE__ */ jsx12("button", { ref: cancelRef, type: "button", className: "db-git-secondary-btn", onClick: reject, children: request.cancelLabel ?? "Cancel" }),
3938
+ /* @__PURE__ */ jsx12(
3701
3939
  "button",
3702
3940
  {
3703
3941
  ref: confirmRef,
@@ -3708,7 +3946,7 @@ function ConfirmDialog({ request, onSettle }) {
3708
3946
  }
3709
3947
  )
3710
3948
  ] }),
3711
- children: /* @__PURE__ */ jsx11("p", { className: "db-dialog-message", children: request.message })
3949
+ children: /* @__PURE__ */ jsx12("p", { className: "db-dialog-message", children: request.message })
3712
3950
  }
3713
3951
  );
3714
3952
  }
@@ -3853,6 +4091,7 @@ function loadLastState(storage = localStorage) {
3853
4091
  var WELCOME_GATEWAY_KEY = "docblocks:welcomeGatewayDismissed";
3854
4092
  var SIDEBAR_WIDTH_KEY = "docblocks:sidebarWidth";
3855
4093
  var VIEW_PREFERENCES_KEY = "docblocks:viewPreferences";
4094
+ var FILE_EXPLORER_SORT_MODE_KEY = "docblocks:fileExplorerSortMode";
3856
4095
  var SIDEBAR_WIDTH_DEFAULT = 320;
3857
4096
  var SIDEBAR_WIDTH_MIN = 320;
3858
4097
  var SIDEBAR_WIDTH_MAX = 600;
@@ -3892,6 +4131,19 @@ function saveSidebarWidth(px) {
3892
4131
  } catch {
3893
4132
  }
3894
4133
  }
4134
+ function loadFileExplorerSortMode() {
4135
+ try {
4136
+ return localStorage.getItem(FILE_EXPLORER_SORT_MODE_KEY) === "last-modified" ? "last-modified" : "name";
4137
+ } catch {
4138
+ return "name";
4139
+ }
4140
+ }
4141
+ function saveFileExplorerSortMode(mode) {
4142
+ try {
4143
+ localStorage.setItem(FILE_EXPLORER_SORT_MODE_KEY, mode);
4144
+ } catch {
4145
+ }
4146
+ }
3895
4147
  function loadViewPreferences() {
3896
4148
  try {
3897
4149
  const raw = localStorage.getItem(VIEW_PREFERENCES_KEY);
@@ -3919,7 +4171,7 @@ function saveViewPreferences(preferences) {
3919
4171
 
3920
4172
  // src/DocBlocksShell/UpdateAvailableNotice.tsx
3921
4173
  import { useState as useState14 } from "react";
3922
- import { Fragment as Fragment6, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
4174
+ import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3923
4175
  var UPDATE_PROMPT_ID = "db-update-available-prompt";
3924
4176
  function UpdateAvailableNotice({
3925
4177
  available,
@@ -3928,10 +4180,11 @@ function UpdateAvailableNotice({
3928
4180
  statusBarVisible
3929
4181
  }) {
3930
4182
  const [promptOpen, setPromptOpen] = useState14(false);
4183
+ const [applying, setApplying] = useState14(false);
3931
4184
  if (!available || !onApplyUpdate) return null;
3932
4185
  const promptVisible = promptOpen && !blocked;
3933
4186
  return /* @__PURE__ */ jsxs11(Fragment6, { children: [
3934
- /* @__PURE__ */ jsx12(
4187
+ /* @__PURE__ */ jsx13(
3935
4188
  "button",
3936
4189
  {
3937
4190
  type: "button",
@@ -3952,10 +4205,21 @@ function UpdateAvailableNotice({
3952
4205
  className: `db-update-banner${statusBarVisible ? "" : " db-update-banner--floating"}`,
3953
4206
  role: "alert",
3954
4207
  children: [
3955
- /* @__PURE__ */ jsx12("span", { children: "A new version of DocBlocks is available. Reload to update the editor and site pages." }),
4208
+ /* @__PURE__ */ jsx13("span", { children: "A new version of DocBlocks is available. Reload to update the editor and site pages." }),
3956
4209
  /* @__PURE__ */ jsxs11("div", { className: "db-update-banner-actions", children: [
3957
- /* @__PURE__ */ jsx12("button", { type: "button", onClick: onApplyUpdate, disabled: blocked, children: "Reload" }),
3958
- /* @__PURE__ */ jsx12("button", { type: "button", onClick: () => setPromptOpen(false), children: "Later" })
4210
+ /* @__PURE__ */ jsx13(
4211
+ "button",
4212
+ {
4213
+ type: "button",
4214
+ onClick: () => {
4215
+ setApplying(true);
4216
+ onApplyUpdate();
4217
+ },
4218
+ disabled: blocked || applying,
4219
+ children: applying ? "Updating\u2026" : "Reload"
4220
+ }
4221
+ ),
4222
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => setPromptOpen(false), disabled: applying, children: "Later" })
3959
4223
  ] })
3960
4224
  ]
3961
4225
  }
@@ -4338,7 +4602,7 @@ var WELCOME_DOCUMENT_CONTENT = [
4338
4602
  "",
4339
4603
  "## Agents get document tools, not a blank check {[factCard]}",
4340
4604
  "",
4341
- "The local MCP server can inspect, validate, preview, compare, and convert documents. Results remain temporary session artifacts until they are deliberately saved, and filesystem access begins with explicit roots rather than assumed authority.",
4605
+ "The local MCP server converts plain text or Markdown directly and can optionally inspect, preview, or compare documents. Results remain temporary session artifacts until they are deliberately saved, and filesystem access begins with explicit roots rather than assumed authority.",
4342
4606
  "",
4343
4607
  "## Start with three small moves {[list]}",
4344
4608
  "",
@@ -4356,7 +4620,7 @@ var WELCOME_DOCUMENT_CONTENT = [
4356
4620
  ].join("\n");
4357
4621
 
4358
4622
  // src/DocBlocksShell/DocBlocksShell.tsx
4359
- import { Fragment as Fragment7, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
4623
+ import { Fragment as Fragment7, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
4360
4624
  var editorShellModulePromise = null;
4361
4625
  function loadEditorShell() {
4362
4626
  editorShellModulePromise ?? (editorShellModulePromise = (async () => {
@@ -4642,7 +4906,7 @@ function useIsMobile(breakpoint = 768) {
4642
4906
  return isMobile;
4643
4907
  }
4644
4908
  function FolderGlyph() {
4645
- return /* @__PURE__ */ jsx13(
4909
+ return /* @__PURE__ */ jsx14(
4646
4910
  "svg",
4647
4911
  {
4648
4912
  viewBox: "0 0 24 24",
@@ -4651,7 +4915,7 @@ function FolderGlyph() {
4651
4915
  strokeWidth: "1.5",
4652
4916
  strokeLinejoin: "round",
4653
4917
  "aria-hidden": "true",
4654
- children: /* @__PURE__ */ jsx13("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" })
4918
+ children: /* @__PURE__ */ jsx14("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" })
4655
4919
  }
4656
4920
  );
4657
4921
  }
@@ -4666,8 +4930,8 @@ function FileGlyph() {
4666
4930
  strokeLinejoin: "round",
4667
4931
  "aria-hidden": "true",
4668
4932
  children: [
4669
- /* @__PURE__ */ jsx13("path", { d: "M6 3h8l5 5v12a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z" }),
4670
- /* @__PURE__ */ jsx13("path", { d: "M14 3v5h5" })
4933
+ /* @__PURE__ */ jsx14("path", { d: "M6 3h8l5 5v12a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z" }),
4934
+ /* @__PURE__ */ jsx14("path", { d: "M14 3v5h5" })
4671
4935
  ]
4672
4936
  }
4673
4937
  );
@@ -4983,14 +5247,17 @@ function DocBlocksShell({
4983
5247
  const [selectedFile, setSelectedFile] = useState15(null);
4984
5248
  useDocumentTitle(selectedFile, homeDocumentTitle, homeDocumentPath);
4985
5249
  const exportDestinationAdapter = useMemo3(() => {
4986
- if (!isElectronHost3() || !activeWorkspaceId || !selectedFile) return void 0;
4987
- const documentId = JSON.stringify([activeWorkspaceId, selectedFile]);
4988
- const host = getDocBlocksHost().exports;
4989
- return {
4990
- resolveTarget: (filename) => host.resolveTarget(documentId, filename),
4991
- pickTarget: (filename, currentTarget) => host.pickTarget(documentId, filename, currentTarget?.grantId ?? null),
4992
- saveBlob: async (blob, filename, target) => host.save(documentId, filename, target?.grantId ?? null, await blob.arrayBuffer())
4993
- };
5250
+ if (!selectedFile) return void 0;
5251
+ if (isElectronHost3() && activeWorkspaceId) {
5252
+ const documentId = JSON.stringify([activeWorkspaceId, selectedFile]);
5253
+ const host = getDocBlocksHost().exports;
5254
+ return {
5255
+ resolveTarget: (filename) => host.resolveTarget(documentId, filename),
5256
+ pickTarget: (filename, currentTarget) => host.pickTarget(documentId, filename, currentTarget?.grantId ?? null),
5257
+ saveBlob: async (blob, filename, target) => host.save(documentId, filename, target?.grantId ?? null, await blob.arrayBuffer())
5258
+ };
5259
+ }
5260
+ return createBrowserSaveAsAdapter();
4994
5261
  }, [activeWorkspaceId, selectedFile]);
4995
5262
  const [selectedFolder, setSelectedFolder] = useState15(null);
4996
5263
  const [folderEntries, setFolderEntries] = useState15([]);
@@ -5014,6 +5281,11 @@ function DocBlocksShell({
5014
5281
  return pickEmptyDocumentPrompt();
5015
5282
  }, [editorKey]);
5016
5283
  const [explorerKey, setExplorerKey] = useState15(0);
5284
+ const [fileExplorerSortMode, setFileExplorerSortMode] = useState15(loadFileExplorerSortMode);
5285
+ const handleFileExplorerSortModeChange = useCallback15((mode) => {
5286
+ setFileExplorerSortMode(mode);
5287
+ saveFileExplorerSortMode(mode);
5288
+ }, []);
5017
5289
  const [documentLinkEpoch, setDocumentLinkEpoch] = useState15(0);
5018
5290
  const [initialView, setInitialView] = useState15("wysiwyg");
5019
5291
  const [initialSharedMode, setInitialSharedMode] = useState15(null);
@@ -7400,7 +7672,7 @@ function DocBlocksShell({
7400
7672
  setPinnedAvailability,
7401
7673
  transitionAwayFromDocument
7402
7674
  ]);
7403
- return /* @__PURE__ */ jsx13(
7675
+ return /* @__PURE__ */ jsx14(
7404
7676
  "div",
7405
7677
  {
7406
7678
  className: `db-shell${effectiveCompact ? " db-shell--mobile" : ""}`,
@@ -7410,8 +7682,8 @@ function DocBlocksShell({
7410
7682
  children: /* @__PURE__ */ jsxs12(GitContext.Provider, { value: git, children: [
7411
7683
  promptDialog,
7412
7684
  confirmDialog,
7413
- workspaceStartupError && /* @__PURE__ */ jsx13("div", { className: "db-save-toast db-save-toast--error", role: "alert", "aria-live": "assertive", children: workspaceStartupError }),
7414
- saveToast && /* @__PURE__ */ jsx13(
7685
+ workspaceStartupError && /* @__PURE__ */ jsx14("div", { className: "db-save-toast db-save-toast--error", role: "alert", "aria-live": "assertive", children: workspaceStartupError }),
7686
+ saveToast && /* @__PURE__ */ jsx14(
7415
7687
  "div",
7416
7688
  {
7417
7689
  className: "db-save-toast db-save-toast--" + saveToast.kind,
@@ -7420,22 +7692,22 @@ function DocBlocksShell({
7420
7692
  children: saveToast.message
7421
7693
  }
7422
7694
  ),
7423
- offlineReadyToast && !saveToast && /* @__PURE__ */ jsx13("div", { className: "db-save-toast db-save-toast--success", role: "status", "aria-live": "polite", children: "DocBlocks is ready to work offline." }),
7695
+ offlineReadyToast && !saveToast && /* @__PURE__ */ jsx14("div", { className: "db-save-toast db-save-toast--success", role: "status", "aria-live": "polite", children: "DocBlocks is ready to work offline." }),
7424
7696
  documentSnapshot.conflict && /* @__PURE__ */ jsxs12("div", { className: "db-document-conflict", role: "alert", children: [
7425
- /* @__PURE__ */ jsx13("span", { children: "This document changed outside DocBlocks. Your unsaved version is still intact." }),
7697
+ /* @__PURE__ */ jsx14("span", { children: "This document changed outside DocBlocks. Your unsaved version is still intact." }),
7426
7698
  /* @__PURE__ */ jsxs12("div", { className: "db-document-conflict-actions", children: [
7427
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => void handleKeepLocalDocument(), children: "Keep mine" }),
7428
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => void handleUseExternalDocument(), children: "Reload external" })
7699
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: () => void handleKeepLocalDocument(), children: "Keep mine" }),
7700
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: () => void handleUseExternalDocument(), children: "Reload external" })
7429
7701
  ] })
7430
7702
  ] }),
7431
7703
  storageFull && !documentSnapshot.conflict && /* @__PURE__ */ jsxs12("div", { className: "db-storage-full-banner", role: "alert", children: [
7432
- /* @__PURE__ */ jsx13("span", { children: "Browser storage is full -- changes can\u2019t be saved. Free up space or back up your work now." }),
7704
+ /* @__PURE__ */ jsx14("span", { children: "Browser storage is full -- changes can\u2019t be saved. Free up space or back up your work now." }),
7433
7705
  /* @__PURE__ */ jsxs12("div", { className: "db-storage-full-banner-actions", children: [
7434
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => void handleDownloadAllWorkspaces(), children: "Download all workspaces" }),
7435
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => setStorageFull(false), children: "Dismiss" })
7706
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: () => void handleDownloadAllWorkspaces(), children: "Download all workspaces" }),
7707
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: () => setStorageFull(false), children: "Dismiss" })
7436
7708
  ] })
7437
7709
  ] }),
7438
- workspaceSettingsOpen && activeWorkspaceDescriptor && /* @__PURE__ */ jsx13(
7710
+ workspaceSettingsOpen && activeWorkspaceDescriptor && /* @__PURE__ */ jsx14(
7439
7711
  WorkspaceSettingsDialog,
7440
7712
  {
7441
7713
  workspace: activeWorkspaceDescriptor,
@@ -7454,7 +7726,7 @@ function DocBlocksShell({
7454
7726
  style: effectiveCompact ? void 0 : { width: `${sidebarWidth}px` },
7455
7727
  children: [
7456
7728
  /* @__PURE__ */ jsxs12("div", { className: "db-shell-sidebar-header", children: [
7457
- /* @__PURE__ */ jsx13(
7729
+ /* @__PURE__ */ jsx14(
7458
7730
  AppMenu,
7459
7731
  {
7460
7732
  logoUrl,
@@ -7475,7 +7747,7 @@ function DocBlocksShell({
7475
7747
  appBuildDate
7476
7748
  }
7477
7749
  ),
7478
- /* @__PURE__ */ jsx13(
7750
+ /* @__PURE__ */ jsx14(
7479
7751
  WorkspacePicker,
7480
7752
  {
7481
7753
  activeWorkspaceId,
@@ -7485,7 +7757,7 @@ function DocBlocksShell({
7485
7757
  onCloneRepository: git.available ? () => git.openDialog({ kind: "clone" }) : void 0
7486
7758
  }
7487
7759
  ),
7488
- /* @__PURE__ */ jsx13(
7760
+ /* @__PURE__ */ jsx14(
7489
7761
  WorkspaceSettingsButton,
7490
7762
  {
7491
7763
  onSettings: handleOpenWorkspaceSettings,
@@ -7494,31 +7766,34 @@ function DocBlocksShell({
7494
7766
  onRemove: handleRemoveWorkspace
7495
7767
  }
7496
7768
  ),
7497
- compactLayout && !isMobile && /* @__PURE__ */ jsx13(
7769
+ compactLayout && !isMobile && /* @__PURE__ */ jsx14(
7498
7770
  "button",
7499
7771
  {
7500
7772
  className: "db-restore-split",
7501
7773
  onClick: () => setCompactLayout(false),
7502
7774
  "aria-label": "Restore split view",
7503
7775
  title: "Restore split view",
7504
- children: /* @__PURE__ */ jsx13(SplitViewIcon, {})
7776
+ children: /* @__PURE__ */ jsx14(SplitViewIcon, {})
7505
7777
  }
7506
7778
  ),
7507
- /* @__PURE__ */ jsx13("span", { className: "db-window-drag-grip", "aria-hidden": true })
7779
+ /* @__PURE__ */ jsx14("span", { className: "db-window-drag-grip", "aria-hidden": true })
7508
7780
  ] }),
7509
- git.available && /* @__PURE__ */ jsx13(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx13(
7781
+ git.available && /* @__PURE__ */ jsx14(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx14(
7510
7782
  GitUI,
7511
7783
  {
7512
7784
  onOpenFile: (path) => void handleSelect(path, "file"),
7513
7785
  onWorkspaceCloned: handleWorkspaceCloned
7514
7786
  }
7515
7787
  ) }),
7516
- /* @__PURE__ */ jsx13(
7788
+ /* @__PURE__ */ jsx14(
7517
7789
  FileExplorer,
7518
7790
  {
7519
7791
  provider,
7792
+ metadataRefreshKey: `${documentSnapshot.targetKey ?? ""}:${documentSnapshot.persistedRevision}`,
7520
7793
  activeWorkspaceId,
7521
7794
  activeFilePath: selectedFile,
7795
+ sortMode: fileExplorerSortMode,
7796
+ onSortModeChange: handleFileExplorerSortModeChange,
7522
7797
  pinnedDocuments: pinnedDocumentItems,
7523
7798
  pinnedPaths: activeWorkspacePinnedPaths,
7524
7799
  onPinnedDocumentSelect: (document2) => void handlePinnedDocumentSelect(document2),
@@ -7542,11 +7817,11 @@ function DocBlocksShell({
7542
7817
  className: "db-mobile-first-run",
7543
7818
  "aria-labelledby": "db-mobile-first-run-title",
7544
7819
  children: [
7545
- /* @__PURE__ */ jsx13("p", { className: "db-mobile-first-run-eyebrow", children: "Local-first Markdown editor" }),
7546
- /* @__PURE__ */ jsx13("h1", { id: "db-mobile-first-run-title", children: "Welcome to DocBlocks" }),
7547
- /* @__PURE__ */ jsx13("p", { children: "Write visually, keep plain Markdown underneath, and export the same document in useful formats. Your browser workspace stays on this device." }),
7820
+ /* @__PURE__ */ jsx14("p", { className: "db-mobile-first-run-eyebrow", children: "Local-first Markdown editor" }),
7821
+ /* @__PURE__ */ jsx14("h1", { id: "db-mobile-first-run-title", children: "Welcome to DocBlocks" }),
7822
+ /* @__PURE__ */ jsx14("p", { children: "Write visually, keep plain Markdown underneath, and export the same document in useful formats. Your browser workspace stays on this device." }),
7548
7823
  /* @__PURE__ */ jsxs12("div", { className: "db-mobile-first-run-actions", children: [
7549
- /* @__PURE__ */ jsx13(
7824
+ /* @__PURE__ */ jsx14(
7550
7825
  "button",
7551
7826
  {
7552
7827
  type: "button",
@@ -7557,7 +7832,7 @@ function DocBlocksShell({
7557
7832
  children: "Tour the welcome document"
7558
7833
  }
7559
7834
  ),
7560
- /* @__PURE__ */ jsx13(
7835
+ /* @__PURE__ */ jsx14(
7561
7836
  "button",
7562
7837
  {
7563
7838
  type: "button",
@@ -7571,14 +7846,14 @@ function DocBlocksShell({
7571
7846
  }
7572
7847
  ),
7573
7848
  /* @__PURE__ */ jsxs12("div", { className: "db-shell-sidebar-footer", children: [
7574
- /* @__PURE__ */ jsx13("a", { href: "https://docblocks.com/docs/", target: "_blank", rel: "noopener noreferrer", children: "Docs" }),
7575
- /* @__PURE__ */ jsx13("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
7576
- /* @__PURE__ */ jsx13("a", { href: "https://docblocks.com/terms/", target: "_blank", rel: "noopener noreferrer", children: "Terms" }),
7577
- /* @__PURE__ */ jsx13("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
7578
- /* @__PURE__ */ jsx13("a", { href: issueReportUrl, target: "_blank", rel: "noopener noreferrer", children: "Report issue" }),
7849
+ /* @__PURE__ */ jsx14("a", { href: "https://docblocks.com/docs/", target: "_blank", rel: "noopener noreferrer", children: "Docs" }),
7850
+ /* @__PURE__ */ jsx14("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
7851
+ /* @__PURE__ */ jsx14("a", { href: "https://docblocks.com/terms/", target: "_blank", rel: "noopener noreferrer", children: "Terms" }),
7852
+ /* @__PURE__ */ jsx14("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
7853
+ /* @__PURE__ */ jsx14("a", { href: issueReportUrl, target: "_blank", rel: "noopener noreferrer", children: "Report issue" }),
7579
7854
  showBrowserStorageWarning && /* @__PURE__ */ jsxs12(Fragment7, { children: [
7580
- /* @__PURE__ */ jsx13("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
7581
- /* @__PURE__ */ jsx13(
7855
+ /* @__PURE__ */ jsx14("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
7856
+ /* @__PURE__ */ jsx14(
7582
7857
  "button",
7583
7858
  {
7584
7859
  type: "button",
@@ -7593,7 +7868,7 @@ function DocBlocksShell({
7593
7868
  ]
7594
7869
  }
7595
7870
  ),
7596
- !effectiveCompact && /* @__PURE__ */ jsx13(
7871
+ !effectiveCompact && /* @__PURE__ */ jsx14(
7597
7872
  "div",
7598
7873
  {
7599
7874
  className: "db-shell-sidebar-resizer",
@@ -7617,11 +7892,11 @@ function DocBlocksShell({
7617
7892
  },
7618
7893
  children: [
7619
7894
  selectedFile && mediaProvider ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
7620
- /* @__PURE__ */ jsx13(
7895
+ /* @__PURE__ */ jsx14(
7621
7896
  Suspense2,
7622
7897
  {
7623
- fallback: /* @__PURE__ */ jsx13("div", { className: "db-shell-empty", role: "status", children: "Loading your document\u2026" }),
7624
- children: /* @__PURE__ */ jsx13(
7898
+ fallback: /* @__PURE__ */ jsx14("div", { className: "db-shell-empty", role: "status", children: "Loading your document\u2026" }),
7899
+ children: /* @__PURE__ */ jsx14(
7625
7900
  EditorShell,
7626
7901
  {
7627
7902
  initialMarkdown: editorContent,
@@ -7647,32 +7922,33 @@ function DocBlocksShell({
7647
7922
  versioningAutoSaveIdleMs,
7648
7923
  onSaveVersion,
7649
7924
  statusBarSlotRight,
7650
- toolbarSlotLeft: effectiveCompact ? /* @__PURE__ */ jsx13(
7925
+ toolbarSlotLeft: effectiveCompact ? /* @__PURE__ */ jsx14(
7651
7926
  "button",
7652
7927
  {
7653
7928
  className: "db-mobile-back",
7654
7929
  onClick: () => setMobileShowEditor(false),
7655
7930
  "aria-label": "Show file list",
7656
- children: /* @__PURE__ */ jsx13("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx13(FolderGlyph, {}) })
7931
+ children: /* @__PURE__ */ jsx14("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx14(FolderGlyph, {}) })
7657
7932
  }
7658
7933
  ) : void 0,
7659
7934
  toolbarSlotRight: /* @__PURE__ */ jsxs12(Fragment7, { children: [
7660
- compactLayout && !isMobile && /* @__PURE__ */ jsx13(
7935
+ compactLayout && !isMobile && /* @__PURE__ */ jsx14(
7661
7936
  "button",
7662
7937
  {
7663
7938
  className: "db-restore-split",
7664
7939
  onClick: () => setCompactLayout(false),
7665
7940
  "aria-label": "Restore split view",
7666
7941
  title: "Restore split view",
7667
- children: /* @__PURE__ */ jsx13(SplitViewIcon, {})
7942
+ children: /* @__PURE__ */ jsx14(SplitViewIcon, {})
7668
7943
  }
7669
7944
  ),
7670
- git.repo && /* @__PURE__ */ jsx13(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx13(GitToolbarControl, { selectedFile }) }),
7671
- /* @__PURE__ */ jsx13(
7945
+ git.repo && /* @__PURE__ */ jsx14(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx14(GitToolbarControl, { selectedFile }) }),
7946
+ /* @__PURE__ */ jsx14(
7672
7947
  ExportToolbarControls,
7673
7948
  {
7674
7949
  selectedFile,
7675
7950
  mediaContainer: mediaContainerRef.current,
7951
+ mediaProvider,
7676
7952
  destinationAdapter: exportDestinationAdapter,
7677
7953
  colorScheme: resolvedTheme,
7678
7954
  videoExportPalette: DOCBLOCKS_VIDEO_EXPORT_PALETTE,
@@ -7689,12 +7965,12 @@ function DocBlocksShell({
7689
7965
  showWelcomeGateway && !isMobile && /* @__PURE__ */ jsxs12("div", { className: "db-welcome-gateway", role: "note", "aria-label": "Welcome tip", children: [
7690
7966
  /* @__PURE__ */ jsxs12("span", { className: "db-welcome-gateway-text", children: [
7691
7967
  "You\u2019re watching this welcome doc in ",
7692
- /* @__PURE__ */ jsx13("strong", { children: "Slideshow" }),
7968
+ /* @__PURE__ */ jsx14("strong", { children: "Slideshow" }),
7693
7969
  " ",
7694
7970
  "view\u2014 it\u2019s a regular markdown file, and so is everything you\u2019ll write."
7695
7971
  ] }),
7696
- /* @__PURE__ */ jsx13("button", { className: "db-welcome-gateway-cta", onClick: handleStartWriting, children: "Start writing" }),
7697
- /* @__PURE__ */ jsx13(
7972
+ /* @__PURE__ */ jsx14("button", { className: "db-welcome-gateway-cta", onClick: handleStartWriting, children: "Start writing" }),
7973
+ /* @__PURE__ */ jsx14(
7698
7974
  "button",
7699
7975
  {
7700
7976
  className: "db-welcome-gateway-dismiss",
@@ -7707,20 +7983,20 @@ function DocBlocksShell({
7707
7983
  ] })
7708
7984
  ] }) : selectedFolder ? /* @__PURE__ */ jsxs12("div", { className: "db-folder-view", children: [
7709
7985
  effectiveCompact && /* @__PURE__ */ jsxs12("button", { className: "db-mobile-back", onClick: () => setMobileShowEditor(false), children: [
7710
- /* @__PURE__ */ jsx13("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx13(FolderGlyph, {}) }),
7986
+ /* @__PURE__ */ jsx14("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx14(FolderGlyph, {}) }),
7711
7987
  "Back to files"
7712
7988
  ] }),
7713
7989
  /* @__PURE__ */ jsxs12("div", { className: "db-folder-view-header", children: [
7714
- /* @__PURE__ */ jsx13("span", { className: "db-folder-view-icon", children: /* @__PURE__ */ jsx13(FolderGlyph, {}) }),
7715
- /* @__PURE__ */ jsx13("span", { className: "db-folder-view-path", children: selectedFolder })
7990
+ /* @__PURE__ */ jsx14("span", { className: "db-folder-view-icon", children: /* @__PURE__ */ jsx14(FolderGlyph, {}) }),
7991
+ /* @__PURE__ */ jsx14("span", { className: "db-folder-view-path", children: selectedFolder })
7716
7992
  ] }),
7717
- visibleFolderEntries.length === 0 ? /* @__PURE__ */ jsx13("p", { className: "db-folder-view-empty", children: "This folder is empty." }) : /* @__PURE__ */ jsx13("ul", { className: "db-folder-view-list", children: visibleFolderEntries.map((entry) => /* @__PURE__ */ jsxs12(
7993
+ visibleFolderEntries.length === 0 ? /* @__PURE__ */ jsx14("p", { className: "db-folder-view-empty", children: "This folder is empty." }) : /* @__PURE__ */ jsx14("ul", { className: "db-folder-view-list", children: visibleFolderEntries.map((entry) => /* @__PURE__ */ jsxs12(
7718
7994
  "li",
7719
7995
  {
7720
7996
  className: "db-folder-view-item",
7721
7997
  onClick: () => handleSelect(entry.path, entry.kind),
7722
7998
  children: [
7723
- /* @__PURE__ */ jsx13("span", { className: "db-folder-view-item-icon", children: entry.kind === "directory" ? /* @__PURE__ */ jsx13(FolderGlyph, {}) : /* @__PURE__ */ jsx13(FileGlyph, {}) }),
7999
+ /* @__PURE__ */ jsx14("span", { className: "db-folder-view-item-icon", children: entry.kind === "directory" ? /* @__PURE__ */ jsx14(FolderGlyph, {}) : /* @__PURE__ */ jsx14(FileGlyph, {}) }),
7724
8000
  entry.name
7725
8001
  ]
7726
8002
  },
@@ -7728,16 +8004,16 @@ function DocBlocksShell({
7728
8004
  )) })
7729
8005
  ] }) : /* @__PURE__ */ jsxs12("div", { className: "db-shell-empty db-shell-empty--workspace", children: [
7730
8006
  effectiveCompact && /* @__PURE__ */ jsxs12("button", { className: "db-mobile-back", onClick: () => setMobileShowEditor(false), children: [
7731
- /* @__PURE__ */ jsx13("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx13(FolderGlyph, {}) }),
8007
+ /* @__PURE__ */ jsx14("span", { className: "db-mobile-files-icon", children: /* @__PURE__ */ jsx14(FolderGlyph, {}) }),
7732
8008
  "Back to files"
7733
8009
  ] }),
7734
8010
  /* @__PURE__ */ jsxs12("div", { className: "db-workspace-empty-content", children: [
7735
- /* @__PURE__ */ jsx13("span", { className: "db-workspace-empty-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx13(FileGlyph, {}) }),
7736
- /* @__PURE__ */ jsx13("h1", { children: activeWorkspaceDescriptor?.name ?? "Workspace" }),
7737
- /* @__PURE__ */ jsx13("p", { children: "Choose a Markdown document from the sidebar, or create a new one." }),
8011
+ /* @__PURE__ */ jsx14("span", { className: "db-workspace-empty-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx14(FileGlyph, {}) }),
8012
+ /* @__PURE__ */ jsx14("h1", { children: activeWorkspaceDescriptor?.name ?? "Workspace" }),
8013
+ /* @__PURE__ */ jsx14("p", { children: "Choose a Markdown document from the sidebar, or create a new one." }),
7738
8014
  /* @__PURE__ */ jsxs12("div", { className: "db-workspace-empty-actions", children: [
7739
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => void handleNewFile(), children: "New document" }),
7740
- /* @__PURE__ */ jsx13(
8015
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: () => void handleNewFile(), children: "New document" }),
8016
+ /* @__PURE__ */ jsx14(
7741
8017
  "button",
7742
8018
  {
7743
8019
  type: "button",
@@ -7746,7 +8022,7 @@ function DocBlocksShell({
7746
8022
  children: "New folder"
7747
8023
  }
7748
8024
  ),
7749
- (isElectronHost3() || typeof globalThis.showDirectoryPicker === "function") && /* @__PURE__ */ jsx13(
8025
+ (isElectronHost3() || typeof globalThis.showDirectoryPicker === "function") && /* @__PURE__ */ jsx14(
7750
8026
  "button",
7751
8027
  {
7752
8028
  type: "button",
@@ -7756,10 +8032,10 @@ function DocBlocksShell({
7756
8032
  }
7757
8033
  )
7758
8034
  ] }),
7759
- /* @__PURE__ */ jsx13("p", { className: "db-workspace-empty-hint", children: "Browser workspaces stay on this device. Use the sidebar backup action to keep a portable copy." })
8035
+ /* @__PURE__ */ jsx14("p", { className: "db-workspace-empty-hint", children: "Browser workspaces stay on this device. Use the sidebar backup action to keep a portable copy." })
7760
8036
  ] })
7761
8037
  ] }),
7762
- /* @__PURE__ */ jsx13(
8038
+ /* @__PURE__ */ jsx14(
7763
8039
  UpdateAvailableNotice,
7764
8040
  {
7765
8041
  available: updateAvailable,