@bendyline/docblocks-react 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/THIRD_PARTY_NOTICES.txt +457 -50
- package/dist/{ExportDialog-VBWHFJ2R.js → ExportDialog-Q4VWI43H.js} +2 -2
- package/dist/{ExportToolbarControls-N3TCL5DD.js → ExportToolbarControls-QYLBRWM7.js} +8 -8
- package/dist/GitGrantNotice-I2VNKPLH.js +29 -0
- package/dist/{GitToolbarControl-VJVK2B4X.js → GitToolbarControl-O5AXBC6T.js} +5 -3
- package/dist/{GitUI-CAKFVKWY.js → GitUI-L5T3XHZG.js} +68 -14
- package/dist/{ShareDialog-PAMOQQFB.js → ShareDialog-4OX3UPJ4.js} +150 -3
- package/dist/calculation/index.d.ts +27 -0
- package/dist/calculation/index.js +16 -0
- package/dist/chunk-6E635KCJ.js +11 -0
- package/dist/chunk-DUKTAKB4.js +83 -0
- package/dist/{chunk-VRRL6VTD.js → chunk-Q6XNIKDG.js} +63 -0
- package/dist/{chunk-HFYPTTCH.js → chunk-V2ENBGUA.js} +0 -9
- package/dist/export/index.js +5 -5
- package/dist/index.d.ts +45 -8
- package/dist/index.js +952 -511
- package/dist/proofing/index.d.ts +112 -0
- package/dist/proofing/index.js +50 -0
- package/dist/settings/index.d.ts +37 -1
- package/dist/settings/index.js +11 -3
- package/package.json +22 -9
- package/src/styles/docblocks.css +443 -97
- package/dist/{chunk-SIIEGOHY.js → chunk-FMDLZ4ZG.js} +3 -3
package/dist/index.js
CHANGED
|
@@ -1,66 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createBrowserSaveAsAdapter
|
|
3
|
+
} from "./chunk-UMEDHMT7.js";
|
|
1
4
|
import {
|
|
2
5
|
BADGE_GLYPHS,
|
|
3
6
|
BADGE_LABELS,
|
|
4
|
-
GitContext,
|
|
5
7
|
buildBadgeMap,
|
|
6
8
|
conflictedPaths,
|
|
7
|
-
isFileDirty
|
|
9
|
+
isFileDirty
|
|
10
|
+
} from "./chunk-V2ENBGUA.js";
|
|
11
|
+
import {
|
|
12
|
+
useMenuKeyboard
|
|
13
|
+
} from "./chunk-MRUK56JS.js";
|
|
14
|
+
import {
|
|
15
|
+
GitContext,
|
|
8
16
|
useGitContext
|
|
9
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-6E635KCJ.js";
|
|
10
18
|
import {
|
|
11
19
|
createImageSaveOutput,
|
|
12
20
|
updateExportTargetExtension
|
|
13
21
|
} from "./chunk-FNSRCCBC.js";
|
|
22
|
+
import {
|
|
23
|
+
runExport
|
|
24
|
+
} from "./chunk-ODYNOPC3.js";
|
|
25
|
+
import {
|
|
26
|
+
buildExportFilename
|
|
27
|
+
} from "./chunk-M5Y5WO7Z.js";
|
|
28
|
+
import {
|
|
29
|
+
createLocalProofingIgnoreStore
|
|
30
|
+
} from "./chunk-DUKTAKB4.js";
|
|
14
31
|
import {
|
|
15
32
|
AccentColorSettings,
|
|
16
33
|
DB_CHROME_COLORS,
|
|
34
|
+
DEFAULT_PROOFING_PREFERENCES,
|
|
17
35
|
DEFAULT_WRITE_CANVAS_FONT_SCHEME,
|
|
18
36
|
DEFAULT_WRITE_CANVAS_PREFERENCES,
|
|
37
|
+
ProofingSettingsControls,
|
|
19
38
|
SettingsDialog,
|
|
20
39
|
ThemeSettings,
|
|
21
40
|
WRITE_CANVAS_FONT_SCHEMES,
|
|
22
41
|
WriteCanvasSettingsControls,
|
|
23
42
|
loadAccentColor,
|
|
43
|
+
loadProofingPreferences,
|
|
24
44
|
loadThemePreference,
|
|
25
45
|
loadWriteCanvasPreferences,
|
|
26
46
|
resolveWriteCanvasFonts,
|
|
27
47
|
saveAccentColor,
|
|
48
|
+
saveProofingPreferences,
|
|
28
49
|
saveThemePreference,
|
|
29
50
|
saveWriteCanvasPreferences
|
|
30
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-Q6XNIKDG.js";
|
|
31
52
|
import {
|
|
32
53
|
pickEmptyDocumentPrompt,
|
|
33
54
|
useResponsivePreviewViewportPreset
|
|
34
55
|
} from "./chunk-JDJVRDOP.js";
|
|
35
56
|
import {
|
|
36
57
|
ExportDialog
|
|
37
|
-
} from "./chunk-
|
|
38
|
-
import {
|
|
39
|
-
runExport
|
|
40
|
-
} from "./chunk-ODYNOPC3.js";
|
|
41
|
-
import {
|
|
42
|
-
createBrowserSaveAsAdapter
|
|
43
|
-
} from "./chunk-UMEDHMT7.js";
|
|
44
|
-
import {
|
|
45
|
-
useMenuKeyboard
|
|
46
|
-
} from "./chunk-MRUK56JS.js";
|
|
58
|
+
} from "./chunk-FMDLZ4ZG.js";
|
|
47
59
|
import "./chunk-YBEYTVU2.js";
|
|
48
|
-
import {
|
|
49
|
-
Dialog
|
|
50
|
-
} from "./chunk-LG6HAWCK.js";
|
|
51
|
-
import {
|
|
52
|
-
buildExportFilename
|
|
53
|
-
} from "./chunk-M5Y5WO7Z.js";
|
|
54
60
|
import {
|
|
55
61
|
DEFAULT_OPTIONS,
|
|
56
62
|
loadLastExportOptions
|
|
57
63
|
} from "./chunk-EBWYGTN7.js";
|
|
64
|
+
import {
|
|
65
|
+
Dialog
|
|
66
|
+
} from "./chunk-LG6HAWCK.js";
|
|
58
67
|
|
|
59
68
|
// src/FileExplorer/FileExplorer.tsx
|
|
60
69
|
import { useCallback as useCallback4, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4 } from "react";
|
|
61
70
|
import {
|
|
62
71
|
isFileSystemMoveStateError,
|
|
63
|
-
parseWorkspacePath as
|
|
72
|
+
parseWorkspacePath as parseWorkspacePath4
|
|
64
73
|
} from "@bendyline/docblocks/filesystem";
|
|
65
74
|
|
|
66
75
|
// src/FileExplorer/useFileTree.ts
|
|
@@ -98,6 +107,22 @@ function equivalentPathKeys(path) {
|
|
|
98
107
|
function hasEquivalentPath(paths, path) {
|
|
99
108
|
return equivalentPathKeys(path).some((candidate) => paths.has(candidate));
|
|
100
109
|
}
|
|
110
|
+
function sameEntry(left, right) {
|
|
111
|
+
if (left.kind !== right.kind || left.name !== right.name || left.path !== right.path)
|
|
112
|
+
return false;
|
|
113
|
+
if (left.kind === "file" && right.kind === "file") {
|
|
114
|
+
return left.lastModified === right.lastModified;
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
function reconcileEntries(current, incoming) {
|
|
119
|
+
const currentByPath = new Map(current.map((entry) => [entry.path, entry]));
|
|
120
|
+
const reconciled = incoming.map((entry) => {
|
|
121
|
+
const previous = currentByPath.get(entry.path);
|
|
122
|
+
return previous && sameEntry(previous, entry) ? previous : entry;
|
|
123
|
+
});
|
|
124
|
+
return reconciled.length === current.length && reconciled.every((entry, index) => entry === current[index]) ? current : reconciled;
|
|
125
|
+
}
|
|
101
126
|
async function readProviderDirectory(provider, path) {
|
|
102
127
|
const canonical = parseWorkspacePath(path);
|
|
103
128
|
const readOnce = async () => {
|
|
@@ -173,7 +198,7 @@ function useFileTree(provider, metadataRefreshKey, metadataRefreshPath) {
|
|
|
173
198
|
try {
|
|
174
199
|
const root = await readProviderDirectory(sourceProvider, "");
|
|
175
200
|
if (!isCurrent()) return;
|
|
176
|
-
setEntries(root);
|
|
201
|
+
setEntries((current) => reconcileEntries(current, root));
|
|
177
202
|
setRootIssue(null);
|
|
178
203
|
} catch (caught) {
|
|
179
204
|
if (isCurrent()) setRootIssue(readIssue(caught, ""));
|
|
@@ -192,8 +217,11 @@ function useFileTree(provider, metadataRefreshKey, metadataRefreshPath) {
|
|
|
192
217
|
const children = await readProviderDirectory(sourceProvider, dirPath);
|
|
193
218
|
if (!isCurrent()) return;
|
|
194
219
|
setChildEntries((prev) => {
|
|
220
|
+
const current = prev.get(canonical) ?? [];
|
|
221
|
+
const reconciled = reconcileEntries(current, children);
|
|
222
|
+
if (prev.has(canonical) && reconciled === current) return prev;
|
|
195
223
|
const next = new Map(prev);
|
|
196
|
-
next.set(canonical,
|
|
224
|
+
next.set(canonical, reconciled);
|
|
197
225
|
return next;
|
|
198
226
|
});
|
|
199
227
|
setChildIssues((prev) => {
|
|
@@ -260,7 +288,7 @@ function useFileTree(provider, metadataRefreshKey, metadataRefreshPath) {
|
|
|
260
288
|
[loadChildren]
|
|
261
289
|
);
|
|
262
290
|
const refresh = useCallback(async () => {
|
|
263
|
-
await loadRoot();
|
|
291
|
+
await loadRoot(false);
|
|
264
292
|
const expandedPaths = [...expanded];
|
|
265
293
|
for (const dirPath of expandedPaths) {
|
|
266
294
|
await loadChildren(dirPath);
|
|
@@ -334,18 +362,21 @@ function useFileTree(provider, metadataRefreshKey, metadataRefreshPath) {
|
|
|
334
362
|
directoriesToRefresh.clear();
|
|
335
363
|
drainRefreshes();
|
|
336
364
|
};
|
|
337
|
-
const
|
|
365
|
+
const requestDirectoryRefresh = (path) => {
|
|
338
366
|
if (disposed || fullRefreshRequested) return;
|
|
339
367
|
directoriesToRefresh.add(workspacePathDirname(parseWorkspacePath(path)));
|
|
340
368
|
drainRefreshes();
|
|
341
369
|
};
|
|
342
370
|
const subscription = providerV2.watch(
|
|
343
371
|
(event) => {
|
|
344
|
-
if (event.type
|
|
345
|
-
|
|
346
|
-
|
|
372
|
+
if (event.type !== "overflow") {
|
|
373
|
+
requestDirectoryRefresh(event.path);
|
|
374
|
+
if (event.type === "moved" && event.destinationPath !== null) {
|
|
375
|
+
requestDirectoryRefresh(event.destinationPath);
|
|
376
|
+
}
|
|
377
|
+
} else {
|
|
378
|
+
requestRefresh();
|
|
347
379
|
}
|
|
348
|
-
requestRefresh();
|
|
349
380
|
},
|
|
350
381
|
{
|
|
351
382
|
onError: (caught) => {
|
|
@@ -499,6 +530,9 @@ function NewFileIcon() {
|
|
|
499
530
|
function NewFolderIcon() {
|
|
500
531
|
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-folder-plus" });
|
|
501
532
|
}
|
|
533
|
+
function OpenFolderIcon() {
|
|
534
|
+
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-folder-open" });
|
|
535
|
+
}
|
|
502
536
|
function SortByNameIcon() {
|
|
503
537
|
return /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: "fa-solid fa-arrow-down-a-z" });
|
|
504
538
|
}
|
|
@@ -1571,46 +1605,609 @@ function filterVisibleFileEntries(entries) {
|
|
|
1571
1605
|
function compareText(left, right) {
|
|
1572
1606
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
1573
1607
|
}
|
|
1574
|
-
function modifiedTime(entry) {
|
|
1575
|
-
if (entry.kind !== "file" || !entry.lastModified) return null;
|
|
1576
|
-
const timestamp = Date.parse(entry.lastModified);
|
|
1577
|
-
return Number.isNaN(timestamp) ? null : timestamp;
|
|
1608
|
+
function modifiedTime(entry) {
|
|
1609
|
+
if (entry.kind !== "file" || !entry.lastModified) return null;
|
|
1610
|
+
const timestamp = Date.parse(entry.lastModified);
|
|
1611
|
+
return Number.isNaN(timestamp) ? null : timestamp;
|
|
1612
|
+
}
|
|
1613
|
+
function sortFileEntries(entries, mode) {
|
|
1614
|
+
return [...entries].sort((left, right) => {
|
|
1615
|
+
if (left.kind !== right.kind) return left.kind === "directory" ? -1 : 1;
|
|
1616
|
+
if (left.kind === "directory" || right.kind === "directory" || mode === "name") {
|
|
1617
|
+
return compareText(left.name, right.name);
|
|
1618
|
+
}
|
|
1619
|
+
const leftTime = modifiedTime(left);
|
|
1620
|
+
const rightTime = modifiedTime(right);
|
|
1621
|
+
if (leftTime !== null && rightTime !== null && leftTime !== rightTime) {
|
|
1622
|
+
return rightTime - leftTime;
|
|
1623
|
+
}
|
|
1624
|
+
if (leftTime === null && rightTime !== null) return 1;
|
|
1625
|
+
if (leftTime !== null && rightTime === null) return -1;
|
|
1626
|
+
return compareText(left.name, right.name);
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
// src/DocBlocksShell/outside-in.ts
|
|
1631
|
+
import {
|
|
1632
|
+
FileSystemContentContainer,
|
|
1633
|
+
FsError as FsError3,
|
|
1634
|
+
getFileSystemProviderV2 as getFileSystemProviderV23,
|
|
1635
|
+
parseWorkspacePath as parseWorkspacePath3
|
|
1636
|
+
} from "@bendyline/docblocks/filesystem";
|
|
1637
|
+
import {
|
|
1638
|
+
createFileSystemDocumentTarget
|
|
1639
|
+
} from "@bendyline/docblocks/document";
|
|
1640
|
+
|
|
1641
|
+
// src/DocBlocksShell/provider-io.ts
|
|
1642
|
+
import {
|
|
1643
|
+
FsError as FsError2,
|
|
1644
|
+
getFileSystemProviderV2 as getFileSystemProviderV22,
|
|
1645
|
+
parseWorkspacePath as parseWorkspacePath2
|
|
1646
|
+
} from "@bendyline/docblocks/filesystem";
|
|
1647
|
+
async function providerEntryExists(provider, path) {
|
|
1648
|
+
const providerV2 = getFileSystemProviderV22(provider);
|
|
1649
|
+
return providerV2 ? await providerV2.stat(parseWorkspacePath2(path)) !== null : provider.exists(path);
|
|
1650
|
+
}
|
|
1651
|
+
async function writeProviderText(provider, path, content, mode = "upsert") {
|
|
1652
|
+
const providerV2 = getFileSystemProviderV22(provider);
|
|
1653
|
+
if (providerV2) {
|
|
1654
|
+
await providerV2.writeFile(parseWorkspacePath2(path), new TextEncoder().encode(content), {
|
|
1655
|
+
mode,
|
|
1656
|
+
createParents: true,
|
|
1657
|
+
expectedVersion: mode === "create" ? null : void 0
|
|
1658
|
+
});
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
if (mode === "create" && await provider.exists(path)) {
|
|
1662
|
+
throw new FsError2("already-exists", "File already exists.", { operation: "write", path });
|
|
1663
|
+
}
|
|
1664
|
+
await provider.writeFile(path, content);
|
|
1665
|
+
}
|
|
1666
|
+
async function removeProviderEntry(provider, path) {
|
|
1667
|
+
const providerV2 = getFileSystemProviderV22(provider);
|
|
1668
|
+
if (providerV2) {
|
|
1669
|
+
await providerV2.remove(parseWorkspacePath2(path), { recursive: true, missing: "ignore" });
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
await provider.delete(path);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
// src/DocBlocksShell/outside-in-contract.ts
|
|
1676
|
+
var OUTSIDE_IN_FORMAT_IDS = ["html", "docx", "pdf", "pptx", "xlsx", "csv"];
|
|
1677
|
+
var FORMAT_IDS = new Set(OUTSIDE_IN_FORMAT_IDS);
|
|
1678
|
+
var UPDATE_FROM_MARKDOWN_KEY = "squisq-updatefrommarkdown";
|
|
1679
|
+
var HTML_OUTPUT_KEY = "squisq-html-output";
|
|
1680
|
+
async function loadOutsideInModule() {
|
|
1681
|
+
return await import("@bendyline/squisq-formats/outside-in");
|
|
1682
|
+
}
|
|
1683
|
+
function normalizePath(path) {
|
|
1684
|
+
const leading = path.replace(/\\/g, "/").startsWith("/") ? "/" : "";
|
|
1685
|
+
const parts = path.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
1686
|
+
if (parts.some((part) => part === "." || part === "..")) {
|
|
1687
|
+
throw new Error(`Outside-in paths must be canonical workspace paths: ${path}`);
|
|
1688
|
+
}
|
|
1689
|
+
return leading + parts.join("/");
|
|
1690
|
+
}
|
|
1691
|
+
function join(parent, child) {
|
|
1692
|
+
if (!parent || parent === "/") return parent === "/" ? `/${child}` : child;
|
|
1693
|
+
return `${parent}/${child}`;
|
|
1694
|
+
}
|
|
1695
|
+
function slug(stem) {
|
|
1696
|
+
return stem.normalize("NFKD").replace(/\p{Mark}+/gu, "").toLocaleLowerCase("en-US").replace(/[^\p{Letter}\p{Number}]+/gu, "-").replace(/^-+|-+$/g, "") || "document";
|
|
1697
|
+
}
|
|
1698
|
+
function resolveOutsideInLayout(path) {
|
|
1699
|
+
const targetPath = normalizePath(path);
|
|
1700
|
+
const slash = targetPath.lastIndexOf("/");
|
|
1701
|
+
const parentDirectory = slash < 0 ? "" : slash === 0 ? "/" : targetPath.slice(0, slash);
|
|
1702
|
+
const filename = slash < 0 ? targetPath : targetPath.slice(slash + 1);
|
|
1703
|
+
const dot = filename.lastIndexOf(".");
|
|
1704
|
+
if (dot <= 0) return null;
|
|
1705
|
+
const rawFormat = filename.slice(dot + 1).toLowerCase();
|
|
1706
|
+
const format = rawFormat === "htm" ? "html" : rawFormat;
|
|
1707
|
+
if (!FORMAT_IDS.has(format)) return null;
|
|
1708
|
+
const stem = filename.slice(0, dot);
|
|
1709
|
+
const companionName = `${stem}_files`;
|
|
1710
|
+
const companionDirectory = join(parentDirectory, companionName);
|
|
1711
|
+
const markdownFilename = `${slug(stem)}.md`;
|
|
1712
|
+
const backupDirectory = join(companionDirectory, ".original");
|
|
1713
|
+
const backupFilename = `original.${format}`;
|
|
1714
|
+
return {
|
|
1715
|
+
targetPath,
|
|
1716
|
+
format,
|
|
1717
|
+
parentDirectory,
|
|
1718
|
+
stem,
|
|
1719
|
+
companionName,
|
|
1720
|
+
companionDirectory,
|
|
1721
|
+
markdownFilename,
|
|
1722
|
+
markdownPath: join(companionDirectory, markdownFilename),
|
|
1723
|
+
relativeTargetPath: `../${filename}`,
|
|
1724
|
+
backupDirectory,
|
|
1725
|
+
backupFilename,
|
|
1726
|
+
backupPath: join(backupDirectory, backupFilename)
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
function chooseOutsideInMarkdownPath(layout, paths) {
|
|
1730
|
+
const canonical = normalizePath(layout.markdownPath);
|
|
1731
|
+
const normalized = paths.map(normalizePath);
|
|
1732
|
+
const exact = normalized.find((path) => path === canonical);
|
|
1733
|
+
if (exact) return exact;
|
|
1734
|
+
const folded = normalized.find(
|
|
1735
|
+
(path) => path.toLocaleLowerCase("en-US") === canonical.toLocaleLowerCase("en-US")
|
|
1736
|
+
);
|
|
1737
|
+
if (folded) return folded;
|
|
1738
|
+
const prefix = `${normalizePath(layout.companionDirectory).replace(/\/$/, "")}/`;
|
|
1739
|
+
const markdown = normalized.filter(
|
|
1740
|
+
(path) => path.startsWith(prefix) && !path.slice(prefix.length).includes("/") && path.toLocaleLowerCase("en-US").endsWith(".md")
|
|
1741
|
+
);
|
|
1742
|
+
return markdown.length === 1 ? markdown[0] : null;
|
|
1743
|
+
}
|
|
1744
|
+
async function readOutsideInMetadata(source) {
|
|
1745
|
+
const { readOutsideInMetadata: readMetadata } = await loadOutsideInModule();
|
|
1746
|
+
const metadata = readMetadata(source);
|
|
1747
|
+
return metadata ? {
|
|
1748
|
+
...metadata,
|
|
1749
|
+
updateFromMarkdown: await isOutsideInMarkdownEditingEnabled(source)
|
|
1750
|
+
} : null;
|
|
1751
|
+
}
|
|
1752
|
+
async function withOutsideInMetadata(source, layout) {
|
|
1753
|
+
const { withOutsideInMetadata: addMetadata } = await loadOutsideInModule();
|
|
1754
|
+
return addMetadata(source, layout);
|
|
1755
|
+
}
|
|
1756
|
+
async function isOutsideInMarkdownEditingEnabled(source) {
|
|
1757
|
+
const module = await loadOutsideInModule();
|
|
1758
|
+
if (module.isOutsideInMarkdownEditingEnabled) {
|
|
1759
|
+
return module.isOutsideInMarkdownEditingEnabled(source);
|
|
1760
|
+
}
|
|
1761
|
+
const { parseFrontmatter, splitFrontmatterBlock } = await import("@bendyline/squisq/markdown");
|
|
1762
|
+
const block = splitFrontmatterBlock(source).frontmatter;
|
|
1763
|
+
if (!block) return false;
|
|
1764
|
+
const firstBreak = block.indexOf("\n");
|
|
1765
|
+
if (firstBreak < 0) return false;
|
|
1766
|
+
const yaml = block.slice(firstBreak + 1).replace(/\r?\n---(?:\r?\n)?$/, "");
|
|
1767
|
+
return parseFrontmatter(yaml)?.[UPDATE_FROM_MARKDOWN_KEY] === true;
|
|
1768
|
+
}
|
|
1769
|
+
async function withOutsideInMarkdownEditing(source, layout, enabled = true) {
|
|
1770
|
+
const module = await loadOutsideInModule();
|
|
1771
|
+
if (module.withOutsideInMarkdownEditing) {
|
|
1772
|
+
return module.withOutsideInMarkdownEditing(source, layout, enabled);
|
|
1773
|
+
}
|
|
1774
|
+
const { setFrontmatterValues } = await import("@bendyline/squisq/markdown");
|
|
1775
|
+
return setFrontmatterValues(await withOutsideInMetadata(source, layout), {
|
|
1776
|
+
[UPDATE_FROM_MARKDOWN_KEY]: enabled
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
async function readOutsideInHtmlOutput(source) {
|
|
1780
|
+
const { parseFrontmatter, splitFrontmatterBlock } = await import("@bendyline/squisq/markdown");
|
|
1781
|
+
const block = splitFrontmatterBlock(source).frontmatter;
|
|
1782
|
+
if (!block) return null;
|
|
1783
|
+
const firstBreak = block.indexOf("\n");
|
|
1784
|
+
if (firstBreak < 0) return null;
|
|
1785
|
+
const yaml = block.slice(firstBreak + 1).replace(/\r?\n---(?:\r?\n)?$/, "");
|
|
1786
|
+
const value = parseFrontmatter(yaml)?.[HTML_OUTPUT_KEY];
|
|
1787
|
+
return value === "interactive" || value === "static" ? value : null;
|
|
1788
|
+
}
|
|
1789
|
+
async function withOutsideInHtmlOutput(source, output) {
|
|
1790
|
+
const { setFrontmatterValues } = await import("@bendyline/squisq/markdown");
|
|
1791
|
+
return setFrontmatterValues(source, { [HTML_OUTPUT_KEY]: output });
|
|
1792
|
+
}
|
|
1793
|
+
async function importOutsideInDocument(source, options = {}) {
|
|
1794
|
+
const { importOutsideInDocument: importDocument } = await loadOutsideInModule();
|
|
1795
|
+
const imported = await importDocument(source, options);
|
|
1796
|
+
const layout = resolveOutsideInLayout(source.targetPath);
|
|
1797
|
+
if (!layout) throw new Error(`Outside-in editing does not support "${source.targetPath}".`);
|
|
1798
|
+
return { ...imported, layout };
|
|
1799
|
+
}
|
|
1800
|
+
async function renderOutsideInDocument(source, options = {}) {
|
|
1801
|
+
const { renderOutsideInDocument: renderDocument } = await loadOutsideInModule();
|
|
1802
|
+
return renderDocument(source, options);
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
// src/DocBlocksShell/outside-in.ts
|
|
1806
|
+
var OUTSIDE_IN_EXTENSION = /\.(?:html?|docx|pdf|pptx|xlsx|csv)$/i;
|
|
1807
|
+
var IMAGE_MIME_TYPES = {
|
|
1808
|
+
avif: "image/avif",
|
|
1809
|
+
bmp: "image/bmp",
|
|
1810
|
+
gif: "image/gif",
|
|
1811
|
+
ico: "image/x-icon",
|
|
1812
|
+
jpeg: "image/jpeg",
|
|
1813
|
+
jpg: "image/jpeg",
|
|
1814
|
+
png: "image/png",
|
|
1815
|
+
webp: "image/webp"
|
|
1816
|
+
};
|
|
1817
|
+
var SQUISQ_RUNTIME_DIRECTORY = "_squisq";
|
|
1818
|
+
var SQUISQ_RUNTIME_FILENAME = "squisq-player.js";
|
|
1819
|
+
function withoutLeadingSlash(path) {
|
|
1820
|
+
return parseWorkspacePath3(path);
|
|
1821
|
+
}
|
|
1822
|
+
function withLegacySlash(path, like) {
|
|
1823
|
+
const canonical = withoutLeadingSlash(path);
|
|
1824
|
+
return like.startsWith("/") && canonical ? `/${canonical}` : canonical;
|
|
1825
|
+
}
|
|
1826
|
+
function dirname(path) {
|
|
1827
|
+
const canonical = withoutLeadingSlash(path);
|
|
1828
|
+
const slash = canonical.lastIndexOf("/");
|
|
1829
|
+
return slash < 0 ? "" : canonical.slice(0, slash);
|
|
1830
|
+
}
|
|
1831
|
+
function join2(parent, child) {
|
|
1832
|
+
return parent ? `${parent}/${child}` : child;
|
|
1833
|
+
}
|
|
1834
|
+
function relativePath(fromDirectory, targetPath) {
|
|
1835
|
+
const from = withoutLeadingSlash(fromDirectory).split("/").filter(Boolean);
|
|
1836
|
+
const target = withoutLeadingSlash(targetPath).split("/").filter(Boolean);
|
|
1837
|
+
let shared = 0;
|
|
1838
|
+
while (shared < from.length && shared < target.length && from[shared] === target[shared]) {
|
|
1839
|
+
shared++;
|
|
1840
|
+
}
|
|
1841
|
+
const segments = [...from.slice(shared).map(() => ".."), ...target.slice(shared)];
|
|
1842
|
+
return segments.join("/") || ".";
|
|
1843
|
+
}
|
|
1844
|
+
async function readText(provider, path) {
|
|
1845
|
+
const v2 = getFileSystemProviderV23(provider);
|
|
1846
|
+
if (!v2) return provider.readFile(path);
|
|
1847
|
+
const current = await v2.readFile(parseWorkspacePath3(path));
|
|
1848
|
+
if (!current) return null;
|
|
1849
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(current.data);
|
|
1850
|
+
}
|
|
1851
|
+
async function readBytes(provider, path) {
|
|
1852
|
+
const v2 = getFileSystemProviderV23(provider);
|
|
1853
|
+
if (v2) return (await v2.readFile(parseWorkspacePath3(path)))?.data ?? null;
|
|
1854
|
+
return provider.readBinary(path);
|
|
1855
|
+
}
|
|
1856
|
+
async function writeBytes(provider, path, data, mode = "upsert") {
|
|
1857
|
+
const v2 = getFileSystemProviderV23(provider);
|
|
1858
|
+
if (v2) {
|
|
1859
|
+
await v2.writeFile(parseWorkspacePath3(path), data, {
|
|
1860
|
+
mode,
|
|
1861
|
+
createParents: true,
|
|
1862
|
+
expectedVersion: mode === "create" ? null : void 0
|
|
1863
|
+
});
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
if (mode === "create" && await provider.exists(path)) {
|
|
1867
|
+
throw new FsError3("already-exists", "File already exists.", { operation: "write", path });
|
|
1868
|
+
}
|
|
1869
|
+
await provider.writeBinary(path, data);
|
|
1870
|
+
}
|
|
1871
|
+
async function listCompanionFiles(provider, layout) {
|
|
1872
|
+
try {
|
|
1873
|
+
const entries = await provider.readDirectory(layout.companionDirectory);
|
|
1874
|
+
return entries.filter((entry) => entry.kind === "file").map((entry) => entry.path);
|
|
1875
|
+
} catch (error) {
|
|
1876
|
+
if (error instanceof FsError3 && error.code === "not-found") return [];
|
|
1877
|
+
throw error;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
async function removeOutsideInCompanion(provider, layout) {
|
|
1881
|
+
const providerV2 = getFileSystemProviderV23(provider);
|
|
1882
|
+
if (providerV2) {
|
|
1883
|
+
const path = parseWorkspacePath3(layout.companionDirectory);
|
|
1884
|
+
if (await providerV2.stat(path) !== null) {
|
|
1885
|
+
await providerV2.remove(path, { recursive: true, missing: "ignore" });
|
|
1886
|
+
}
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
if (await provider.exists(layout.companionDirectory)) {
|
|
1890
|
+
await provider.delete(layout.companionDirectory);
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
async function persistImportedMedia(provider, layout, container) {
|
|
1894
|
+
const entries = await container.listFiles();
|
|
1895
|
+
for (const entry of entries) {
|
|
1896
|
+
if (/\.md$/i.test(entry.path)) continue;
|
|
1897
|
+
const data = await container.readFile(entry.path);
|
|
1898
|
+
if (!data) continue;
|
|
1899
|
+
await writeBytes(provider, join2(layout.companionDirectory, entry.path), data, "create");
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
async function loadEditableShellDocument(provider, selectedPath) {
|
|
1903
|
+
const imageExtension = selectedPath.slice(selectedPath.lastIndexOf(".") + 1).toLowerCase();
|
|
1904
|
+
const imageMimeType = IMAGE_MIME_TYPES[imageExtension];
|
|
1905
|
+
if (imageMimeType) {
|
|
1906
|
+
const data = await readBytes(provider, selectedPath);
|
|
1907
|
+
return data === null ? null : {
|
|
1908
|
+
displayPath: selectedPath,
|
|
1909
|
+
sourcePath: selectedPath,
|
|
1910
|
+
content: "",
|
|
1911
|
+
outsideIn: null,
|
|
1912
|
+
outsideInEditingEnabled: false,
|
|
1913
|
+
image: { data, mimeType: imageMimeType }
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
if (!OUTSIDE_IN_EXTENSION.test(selectedPath)) {
|
|
1917
|
+
const content = await readText(provider, selectedPath);
|
|
1918
|
+
return content === null ? null : {
|
|
1919
|
+
displayPath: selectedPath,
|
|
1920
|
+
sourcePath: selectedPath,
|
|
1921
|
+
content,
|
|
1922
|
+
outsideIn: null,
|
|
1923
|
+
outsideInEditingEnabled: true
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
const resolved = resolveOutsideInLayout(selectedPath);
|
|
1927
|
+
if (!resolved) return null;
|
|
1928
|
+
const layout = {
|
|
1929
|
+
...resolved,
|
|
1930
|
+
targetPath: withLegacySlash(resolved.targetPath, selectedPath),
|
|
1931
|
+
companionDirectory: withLegacySlash(resolved.companionDirectory, selectedPath),
|
|
1932
|
+
markdownPath: withLegacySlash(resolved.markdownPath, selectedPath)
|
|
1933
|
+
};
|
|
1934
|
+
const candidates = (await listCompanionFiles(provider, layout)).map(
|
|
1935
|
+
(path) => withLegacySlash(path, selectedPath)
|
|
1936
|
+
);
|
|
1937
|
+
const chosen = chooseOutsideInMarkdownPath(layout, candidates);
|
|
1938
|
+
if (chosen) {
|
|
1939
|
+
const content = await readText(provider, chosen);
|
|
1940
|
+
if (content === null) return null;
|
|
1941
|
+
const metadata = await readOutsideInMetadata(content);
|
|
1942
|
+
if (metadata && metadata.format !== layout.format) {
|
|
1943
|
+
throw new Error(
|
|
1944
|
+
`${chosen} is configured for ${metadata.format}, not ${layout.format}. Rename the rendered file back or repair the companion frontmatter.`
|
|
1945
|
+
);
|
|
1946
|
+
}
|
|
1947
|
+
const linkedContent = await withOutsideInMetadata(content, layout);
|
|
1948
|
+
if (linkedContent !== content) await writeProviderText(provider, chosen, linkedContent);
|
|
1949
|
+
return {
|
|
1950
|
+
displayPath: selectedPath,
|
|
1951
|
+
sourcePath: chosen,
|
|
1952
|
+
content: linkedContent,
|
|
1953
|
+
outsideIn: { ...layout, markdownPath: chosen },
|
|
1954
|
+
outsideInEditingEnabled: await isOutsideInMarkdownEditingEnabled(linkedContent)
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1957
|
+
const rendered = await readBytes(provider, selectedPath);
|
|
1958
|
+
if (!rendered) return null;
|
|
1959
|
+
const imported = await importOutsideInDocument({
|
|
1960
|
+
data: rendered,
|
|
1961
|
+
targetPath: selectedPath
|
|
1962
|
+
});
|
|
1963
|
+
const importedLayout = {
|
|
1964
|
+
...imported.layout,
|
|
1965
|
+
targetPath: withLegacySlash(imported.layout.targetPath, selectedPath),
|
|
1966
|
+
companionDirectory: withLegacySlash(imported.layout.companionDirectory, selectedPath),
|
|
1967
|
+
markdownPath: withLegacySlash(imported.layout.markdownPath, selectedPath)
|
|
1968
|
+
};
|
|
1969
|
+
await persistImportedMedia(provider, importedLayout, imported.container);
|
|
1970
|
+
await writeProviderText(provider, importedLayout.markdownPath, imported.markdown, "create");
|
|
1971
|
+
return {
|
|
1972
|
+
displayPath: selectedPath,
|
|
1973
|
+
sourcePath: importedLayout.markdownPath,
|
|
1974
|
+
content: imported.markdown,
|
|
1975
|
+
outsideIn: importedLayout,
|
|
1976
|
+
outsideInEditingEnabled: false
|
|
1977
|
+
};
|
|
1978
|
+
}
|
|
1979
|
+
async function enableOutsideInMarkdownEditing(provider, document2) {
|
|
1980
|
+
const layout = document2.outsideIn;
|
|
1981
|
+
if (!layout) throw new Error("This file does not support outside-in Markdown editing.");
|
|
1982
|
+
const original = await readBytes(provider, layout.targetPath);
|
|
1983
|
+
if (!original) throw new Error(`The rendered file "${layout.targetPath}" was not found.`);
|
|
1984
|
+
try {
|
|
1985
|
+
await writeBytes(provider, layout.backupPath, original, "create");
|
|
1986
|
+
} catch (error) {
|
|
1987
|
+
if (!(error instanceof FsError3 && error.code === "already-exists")) throw error;
|
|
1988
|
+
}
|
|
1989
|
+
const content = await withOutsideInMarkdownEditing(document2.content, layout);
|
|
1990
|
+
if (content !== document2.content) await writeProviderText(provider, document2.sourcePath, content);
|
|
1991
|
+
return { ...document2, content, outsideIn: layout, outsideInEditingEnabled: true };
|
|
1992
|
+
}
|
|
1993
|
+
async function findRuntimePath(provider, targetPath) {
|
|
1994
|
+
let directory = dirname(targetPath);
|
|
1995
|
+
for (; ; ) {
|
|
1996
|
+
const candidateDirectory = join2(directory, SQUISQ_RUNTIME_DIRECTORY);
|
|
1997
|
+
if (await providerEntryExists(provider, candidateDirectory)) {
|
|
1998
|
+
const providerV2 = getFileSystemProviderV23(provider);
|
|
1999
|
+
if (providerV2) {
|
|
2000
|
+
const entry = await providerV2.stat(parseWorkspacePath3(candidateDirectory));
|
|
2001
|
+
if (entry?.kind !== "directory") {
|
|
2002
|
+
throw new Error(`${candidateDirectory} must be a directory.`);
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
return join2(candidateDirectory, SQUISQ_RUNTIME_FILENAME);
|
|
2006
|
+
}
|
|
2007
|
+
if (!directory) break;
|
|
2008
|
+
directory = dirname(directory);
|
|
2009
|
+
}
|
|
2010
|
+
return join2(SQUISQ_RUNTIME_DIRECTORY, SQUISQ_RUNTIME_FILENAME);
|
|
2011
|
+
}
|
|
2012
|
+
async function writeRuntimeIfNeeded(provider, runtimePath) {
|
|
2013
|
+
const { PLAYER_BUNDLE } = await import("@bendyline/squisq-react/standalone-source");
|
|
2014
|
+
const current = await readText(provider, runtimePath);
|
|
2015
|
+
if (current !== PLAYER_BUNDLE) await writeProviderText(provider, runtimePath, PLAYER_BUNDLE);
|
|
2016
|
+
}
|
|
2017
|
+
async function renderPlainOutsideInHtml(provider, layout, markdown) {
|
|
2018
|
+
const [{ parseMarkdown }, { markdownDocToPlainHtml }] = await Promise.all([
|
|
2019
|
+
import("@bendyline/squisq/markdown"),
|
|
2020
|
+
import("@bendyline/squisq-formats/html")
|
|
2021
|
+
]);
|
|
2022
|
+
const container = new FileSystemContentContainer(provider, layout.companionDirectory);
|
|
2023
|
+
const images = /* @__PURE__ */ new Map();
|
|
2024
|
+
for (const entry of await container.listFiles()) {
|
|
2025
|
+
const outputPath = `${layout.companionName}/${entry.path}`;
|
|
2026
|
+
images.set(entry.path, outputPath);
|
|
2027
|
+
images.set(`./${entry.path}`, outputPath);
|
|
2028
|
+
}
|
|
2029
|
+
return new TextEncoder().encode(
|
|
2030
|
+
markdownDocToPlainHtml(parseMarkdown(markdown), {
|
|
2031
|
+
title: layout.stem,
|
|
2032
|
+
images: images.size > 0 ? images : void 0
|
|
2033
|
+
})
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
async function prepareOutsideInRender(provider, layout, markdown) {
|
|
2037
|
+
const htmlOutput = layout.format === "html" ? await readOutsideInHtmlOutput(markdown) : null;
|
|
2038
|
+
if (htmlOutput === "static") {
|
|
2039
|
+
return {
|
|
2040
|
+
bytes: await renderPlainOutsideInHtml(provider, layout, markdown),
|
|
2041
|
+
runtimePath: null
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
const runtimePath = layout.format === "html" ? await findRuntimePath(provider, layout.targetPath) : null;
|
|
2045
|
+
const outputDirectory = dirname(layout.targetPath);
|
|
2046
|
+
const rendered = await renderOutsideInDocument(
|
|
2047
|
+
{
|
|
2048
|
+
markdown,
|
|
2049
|
+
targetPath: layout.targetPath,
|
|
2050
|
+
container: new FileSystemContentContainer(provider, layout.companionDirectory)
|
|
2051
|
+
},
|
|
2052
|
+
runtimePath ? {
|
|
2053
|
+
html: {
|
|
2054
|
+
playerScriptPath: relativePath(outputDirectory, runtimePath),
|
|
2055
|
+
basePath: relativePath(outputDirectory, layout.companionDirectory)
|
|
2056
|
+
},
|
|
2057
|
+
...htmlOutput === "interactive" ? { formatOptions: { html: { mode: "slideshow" } } } : {}
|
|
2058
|
+
} : {}
|
|
2059
|
+
);
|
|
2060
|
+
return { bytes: rendered.bytes, runtimePath };
|
|
1578
2061
|
}
|
|
1579
|
-
function
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
2062
|
+
async function createNewOutsideInDocument(provider, targetPath, htmlOutput) {
|
|
2063
|
+
const layout = resolveOutsideInLayout(targetPath);
|
|
2064
|
+
if (!layout) throw new Error(`Outside-in editing does not support "${targetPath}".`);
|
|
2065
|
+
if (layout.format !== "html" && htmlOutput !== void 0) {
|
|
2066
|
+
throw new Error("Only Web pages have an HTML output style.");
|
|
2067
|
+
}
|
|
2068
|
+
if (await providerEntryExists(provider, layout.targetPath) || await providerEntryExists(provider, layout.companionDirectory)) {
|
|
2069
|
+
throw new FsError3(
|
|
2070
|
+
"already-exists",
|
|
2071
|
+
"A file or companion folder with that name already exists.",
|
|
2072
|
+
{
|
|
2073
|
+
operation: "write",
|
|
2074
|
+
path: layout.targetPath
|
|
2075
|
+
}
|
|
2076
|
+
);
|
|
2077
|
+
}
|
|
2078
|
+
let content = await withOutsideInMarkdownEditing(`# ${layout.stem}
|
|
2079
|
+
`, layout);
|
|
2080
|
+
if (layout.format === "html") {
|
|
2081
|
+
content = await withOutsideInHtmlOutput(content, htmlOutput ?? "interactive");
|
|
2082
|
+
}
|
|
2083
|
+
const prepared = await prepareOutsideInRender(provider, layout, content);
|
|
2084
|
+
if (prepared.runtimePath) await writeRuntimeIfNeeded(provider, prepared.runtimePath);
|
|
2085
|
+
await writeBytes(provider, layout.targetPath, prepared.bytes, "create");
|
|
2086
|
+
await writeProviderText(provider, layout.markdownPath, content, "create");
|
|
2087
|
+
return {
|
|
2088
|
+
displayPath: layout.targetPath,
|
|
2089
|
+
sourcePath: layout.markdownPath,
|
|
2090
|
+
content,
|
|
2091
|
+
outsideIn: layout,
|
|
2092
|
+
outsideInEditingEnabled: true
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
2095
|
+
function createOutsideInDocumentTarget(provider, layout, onCommitted) {
|
|
2096
|
+
const sourceTarget = createFileSystemDocumentTarget(provider, layout.markdownPath);
|
|
2097
|
+
return {
|
|
2098
|
+
key: `${provider.id}:outside-in:${parseWorkspacePath3(layout.targetPath)}`,
|
|
2099
|
+
async commit(request) {
|
|
2100
|
+
if (!await isOutsideInMarkdownEditingEnabled(request.content)) {
|
|
2101
|
+
throw new Error(
|
|
2102
|
+
"Outside-in editing is read-only until squisq-updatefrommarkdown: true is set."
|
|
2103
|
+
);
|
|
2104
|
+
}
|
|
2105
|
+
const rendered = await prepareOutsideInRender(provider, layout, request.content);
|
|
2106
|
+
await sourceTarget.commit({ ...request, targetKey: sourceTarget.key });
|
|
2107
|
+
if (rendered.runtimePath) await writeRuntimeIfNeeded(provider, rendered.runtimePath);
|
|
2108
|
+
await writeBytes(provider, layout.targetPath, rendered.bytes);
|
|
2109
|
+
onCommitted?.();
|
|
2110
|
+
return {};
|
|
1589
2111
|
}
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
2112
|
+
};
|
|
2113
|
+
}
|
|
2114
|
+
function createOutsideInContentContainer(provider, layout) {
|
|
2115
|
+
return new FileSystemContentContainer(provider, layout.companionDirectory);
|
|
1594
2116
|
}
|
|
1595
2117
|
|
|
1596
|
-
// src/
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
".
|
|
1600
|
-
".md",
|
|
2118
|
+
// src/DocBlocksShell/import-file-types.ts
|
|
2119
|
+
var OUTSIDE_IN_IMPORT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2120
|
+
".csv",
|
|
2121
|
+
".docx",
|
|
1601
2122
|
".html",
|
|
1602
2123
|
".htm",
|
|
1603
|
-
".docx",
|
|
1604
2124
|
".pdf",
|
|
1605
2125
|
".pptx",
|
|
1606
|
-
".xlsx"
|
|
1607
|
-
|
|
1608
|
-
|
|
2126
|
+
".xlsx"
|
|
2127
|
+
]);
|
|
2128
|
+
var BUNDLE_IMPORT_EXTENSIONS = /* @__PURE__ */ new Set([".dbk", ".zip"]);
|
|
2129
|
+
var DIRECT_IMPORT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2130
|
+
".avif",
|
|
2131
|
+
".bash",
|
|
2132
|
+
".bmp",
|
|
2133
|
+
".c",
|
|
2134
|
+
".cc",
|
|
2135
|
+
".cpp",
|
|
2136
|
+
".cs",
|
|
2137
|
+
".css",
|
|
2138
|
+
".gif",
|
|
2139
|
+
".go",
|
|
2140
|
+
".h",
|
|
2141
|
+
".hpp",
|
|
2142
|
+
".ico",
|
|
2143
|
+
".ini",
|
|
2144
|
+
".java",
|
|
2145
|
+
".jpeg",
|
|
2146
|
+
".jpg",
|
|
2147
|
+
".js",
|
|
2148
|
+
".json",
|
|
2149
|
+
".jsonc",
|
|
2150
|
+
".jsx",
|
|
2151
|
+
".kt",
|
|
2152
|
+
".kts",
|
|
2153
|
+
".less",
|
|
2154
|
+
".log",
|
|
2155
|
+
".lua",
|
|
2156
|
+
".markdown",
|
|
2157
|
+
".md",
|
|
2158
|
+
".mdown",
|
|
2159
|
+
".mjs",
|
|
2160
|
+
".php",
|
|
2161
|
+
".png",
|
|
2162
|
+
".py",
|
|
2163
|
+
".rb",
|
|
2164
|
+
".rs",
|
|
2165
|
+
".scss",
|
|
2166
|
+
".sh",
|
|
2167
|
+
".sql",
|
|
2168
|
+
".svg",
|
|
2169
|
+
".swift",
|
|
2170
|
+
".toml",
|
|
2171
|
+
".ts",
|
|
2172
|
+
".tsv",
|
|
2173
|
+
".tsx",
|
|
2174
|
+
".txt",
|
|
2175
|
+
".webp",
|
|
2176
|
+
".xml",
|
|
2177
|
+
".yaml",
|
|
2178
|
+
".yml",
|
|
2179
|
+
".zsh"
|
|
1609
2180
|
]);
|
|
2181
|
+
var DIRECT_IMPORT_BASENAMES = /* @__PURE__ */ new Set(["dockerfile", "license", "makefile", "readme"]);
|
|
2182
|
+
function extensionOfFileName(name) {
|
|
2183
|
+
const dot = name.lastIndexOf(".");
|
|
2184
|
+
return dot <= 0 ? "" : name.slice(dot).toLowerCase();
|
|
2185
|
+
}
|
|
2186
|
+
function isSupportedImportFile(file) {
|
|
2187
|
+
const extension = extensionOfFileName(file.name);
|
|
2188
|
+
if (OUTSIDE_IN_IMPORT_EXTENSIONS.has(extension) || BUNDLE_IMPORT_EXTENSIONS.has(extension) || DIRECT_IMPORT_EXTENSIONS.has(extension)) {
|
|
2189
|
+
return true;
|
|
2190
|
+
}
|
|
2191
|
+
const mimeType = file.type.toLowerCase();
|
|
2192
|
+
if (mimeType.startsWith("text/") || mimeType.startsWith("image/")) return true;
|
|
2193
|
+
return !extension && DIRECT_IMPORT_BASENAMES.has(file.name.toLowerCase());
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
// src/FileExplorer/FileExplorer.tsx
|
|
2197
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1610
2198
|
var INTERNAL_DRAG_TYPE = "application/x-docblocks-entry";
|
|
1611
2199
|
var NEW_ITEM_ERROR_ID = "db-new-item-error";
|
|
2200
|
+
var NEW_FILE_EXTENSIONS = {
|
|
2201
|
+
markdown: ".md",
|
|
2202
|
+
docx: ".docx",
|
|
2203
|
+
xlsx: ".xlsx",
|
|
2204
|
+
pdf: ".pdf",
|
|
2205
|
+
"web-interactive": ".html",
|
|
2206
|
+
"web-static": ".html"
|
|
2207
|
+
};
|
|
2208
|
+
var SELECTABLE_FILE_EXTENSION = /\.(?:md|docx|xlsx|pdf|html?)$/i;
|
|
1612
2209
|
function normalisePath2(path) {
|
|
1613
|
-
return
|
|
2210
|
+
return parseWorkspacePath4(path);
|
|
1614
2211
|
}
|
|
1615
2212
|
function hasEquivalentPath2(paths, path) {
|
|
1616
2213
|
const canonical = normalisePath2(path);
|
|
@@ -1657,6 +2254,7 @@ function FileExplorer({
|
|
|
1657
2254
|
onPinnedDocumentDelete,
|
|
1658
2255
|
onTogglePin,
|
|
1659
2256
|
onSelect,
|
|
2257
|
+
onOpenWorkspaceFolder,
|
|
1660
2258
|
actionsForEntry,
|
|
1661
2259
|
onTreeMutation,
|
|
1662
2260
|
onTreeChange,
|
|
@@ -1675,6 +2273,7 @@ function FileExplorer({
|
|
|
1675
2273
|
[pinnedPaths]
|
|
1676
2274
|
);
|
|
1677
2275
|
const [newItemName, setNewItemName] = useState4("");
|
|
2276
|
+
const [newFileFormat, setNewFileFormat] = useState4("markdown");
|
|
1678
2277
|
const [uncontrolledSortMode, setUncontrolledSortMode] = useState4("name");
|
|
1679
2278
|
const selectedSortMode = sortMode ?? uncontrolledSortMode;
|
|
1680
2279
|
const selectSortMode = useCallback4(
|
|
@@ -1709,12 +2308,11 @@ function FileExplorer({
|
|
|
1709
2308
|
const hasSupported = useCallback4((dt) => {
|
|
1710
2309
|
for (const item of Array.from(dt.items)) {
|
|
1711
2310
|
if (item.kind !== "file") continue;
|
|
1712
|
-
const
|
|
1713
|
-
if (!
|
|
1714
|
-
|
|
1715
|
-
if (SUPPORTED_EXTENSIONS.has(ext)) return true;
|
|
2311
|
+
const file = item.getAsFile();
|
|
2312
|
+
if (!file) return true;
|
|
2313
|
+
if (isSupportedImportFile(file)) return true;
|
|
1716
2314
|
}
|
|
1717
|
-
return dt.
|
|
2315
|
+
return Array.from(dt.files).some(isSupportedImportFile);
|
|
1718
2316
|
}, []);
|
|
1719
2317
|
const handleDragEnter = useCallback4(
|
|
1720
2318
|
(e) => {
|
|
@@ -1748,11 +2346,8 @@ function FileExplorer({
|
|
|
1748
2346
|
e.preventDefault();
|
|
1749
2347
|
dragCounter.current = 0;
|
|
1750
2348
|
setDragOver(false);
|
|
1751
|
-
const
|
|
1752
|
-
|
|
1753
|
-
return SUPPORTED_EXTENSIONS.has(ext);
|
|
1754
|
-
});
|
|
1755
|
-
if (supported.length > 0) onImportFiles?.(supported);
|
|
2349
|
+
const files = Array.from(e.dataTransfer.files);
|
|
2350
|
+
if (files.length > 0) onImportFiles?.(files);
|
|
1756
2351
|
},
|
|
1757
2352
|
[onImportFiles]
|
|
1758
2353
|
);
|
|
@@ -1791,9 +2386,24 @@ function FileExplorer({
|
|
|
1791
2386
|
setNewItemCreationPending(true);
|
|
1792
2387
|
try {
|
|
1793
2388
|
if (itemType === "file") {
|
|
1794
|
-
const
|
|
2389
|
+
const stem = name.replace(SELECTABLE_FILE_EXTENSION, "");
|
|
2390
|
+
if (!stem) {
|
|
2391
|
+
setNewItemError("Enter a file name before the extension.");
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
const filename = `${stem}${NEW_FILE_EXTENSIONS[newFileFormat]}`;
|
|
1795
2395
|
createdPath = `${prefix}${filename}`;
|
|
1796
|
-
|
|
2396
|
+
if (newFileFormat === "markdown") {
|
|
2397
|
+
await tree.createFile(createdPath, "");
|
|
2398
|
+
} else {
|
|
2399
|
+
if (!provider) throw new Error("Open a workspace before creating a document.");
|
|
2400
|
+
await createNewOutsideInDocument(
|
|
2401
|
+
provider,
|
|
2402
|
+
createdPath,
|
|
2403
|
+
newFileFormat === "web-static" ? "static" : newFileFormat === "web-interactive" ? "interactive" : void 0
|
|
2404
|
+
);
|
|
2405
|
+
await tree.refresh();
|
|
2406
|
+
}
|
|
1797
2407
|
handleSelect(createdPath);
|
|
1798
2408
|
} else if (itemType === "directory") {
|
|
1799
2409
|
await tree.createDirectory(createdPath);
|
|
@@ -1808,7 +2418,7 @@ function FileExplorer({
|
|
|
1808
2418
|
setNewItemName("");
|
|
1809
2419
|
setNewItemType(null);
|
|
1810
2420
|
onTreeChange?.({ type: "create", path: createdPath });
|
|
1811
|
-
}, [newItemName, newItemType, tree, handleSelect
|
|
2421
|
+
}, [newFileFormat, newItemName, newItemType, onTreeChange, provider, tree, handleSelect]);
|
|
1812
2422
|
const handleMoveToWorkspace = useCallback4(async () => {
|
|
1813
2423
|
if (!onMoveToWorkspace || !moveDestinationId || movingToWorkspace) return;
|
|
1814
2424
|
setMovingToWorkspace(true);
|
|
@@ -2136,6 +2746,17 @@ function FileExplorer({
|
|
|
2136
2746
|
)
|
|
2137
2747
|
] }),
|
|
2138
2748
|
/* @__PURE__ */ jsx5("span", { className: "db-explorer-action-divider", "aria-hidden": "true" }),
|
|
2749
|
+
onOpenWorkspaceFolder && /* @__PURE__ */ jsx5(
|
|
2750
|
+
"button",
|
|
2751
|
+
{
|
|
2752
|
+
type: "button",
|
|
2753
|
+
className: "db-explorer-btn",
|
|
2754
|
+
onClick: onOpenWorkspaceFolder,
|
|
2755
|
+
title: "Open this folder",
|
|
2756
|
+
"aria-label": "Open this folder",
|
|
2757
|
+
children: /* @__PURE__ */ jsx5(OpenFolderIcon, {})
|
|
2758
|
+
}
|
|
2759
|
+
),
|
|
2139
2760
|
/* @__PURE__ */ jsx5(
|
|
2140
2761
|
"button",
|
|
2141
2762
|
{
|
|
@@ -2159,6 +2780,7 @@ function FileExplorer({
|
|
|
2159
2780
|
disabled: newItemCreationPending,
|
|
2160
2781
|
onClick: () => {
|
|
2161
2782
|
setNewItemError(null);
|
|
2783
|
+
setNewFileFormat("markdown");
|
|
2162
2784
|
setNewItemType("file");
|
|
2163
2785
|
},
|
|
2164
2786
|
title: "New File",
|
|
@@ -2237,7 +2859,7 @@ function FileExplorer({
|
|
|
2237
2859
|
/* @__PURE__ */ jsxs4(
|
|
2238
2860
|
"form",
|
|
2239
2861
|
{
|
|
2240
|
-
className:
|
|
2862
|
+
className: `db-new-item-row db-new-item-row--${newItemType}`,
|
|
2241
2863
|
"aria-busy": newItemCreationPending,
|
|
2242
2864
|
onSubmit: (e) => {
|
|
2243
2865
|
e.preventDefault();
|
|
@@ -2262,14 +2884,41 @@ function FileExplorer({
|
|
|
2262
2884
|
if (e.key === "Escape") {
|
|
2263
2885
|
setNewItemType(null);
|
|
2264
2886
|
setNewItemName("");
|
|
2887
|
+
setNewFileFormat("markdown");
|
|
2265
2888
|
setNewItemError(null);
|
|
2266
2889
|
}
|
|
2267
2890
|
},
|
|
2268
2891
|
autoFocus: true
|
|
2269
2892
|
}
|
|
2270
2893
|
),
|
|
2271
|
-
newItemType === "file"
|
|
2272
|
-
|
|
2894
|
+
newItemType === "file" ? /* @__PURE__ */ jsxs4("div", { className: "db-new-item-file-controls", children: [
|
|
2895
|
+
/* @__PURE__ */ jsxs4(
|
|
2896
|
+
"select",
|
|
2897
|
+
{
|
|
2898
|
+
className: "db-new-item-format",
|
|
2899
|
+
"aria-label": "New file type",
|
|
2900
|
+
value: newFileFormat,
|
|
2901
|
+
disabled: newItemCreationPending,
|
|
2902
|
+
onChange: (event) => {
|
|
2903
|
+
setNewFileFormat(event.currentTarget.value);
|
|
2904
|
+
setNewItemError(null);
|
|
2905
|
+
},
|
|
2906
|
+
children: [
|
|
2907
|
+
/* @__PURE__ */ jsxs4("optgroup", { label: "Document", children: [
|
|
2908
|
+
/* @__PURE__ */ jsx5("option", { value: "markdown", children: "Markdown (.md)" }),
|
|
2909
|
+
/* @__PURE__ */ jsx5("option", { value: "docx", children: "Word document (.docx)" }),
|
|
2910
|
+
/* @__PURE__ */ jsx5("option", { value: "xlsx", children: "Excel workbook (.xlsx)" }),
|
|
2911
|
+
/* @__PURE__ */ jsx5("option", { value: "pdf", children: "PDF document (.pdf)" })
|
|
2912
|
+
] }),
|
|
2913
|
+
/* @__PURE__ */ jsxs4("optgroup", { label: "Web page", children: [
|
|
2914
|
+
/* @__PURE__ */ jsx5("option", { value: "web-interactive", children: "Web page \u2014 Interactive (.html)" }),
|
|
2915
|
+
/* @__PURE__ */ jsx5("option", { value: "web-static", children: "Web page \u2014 Static (.html)" })
|
|
2916
|
+
] })
|
|
2917
|
+
]
|
|
2918
|
+
}
|
|
2919
|
+
),
|
|
2920
|
+
/* @__PURE__ */ jsx5("button", { type: "submit", className: "db-new-item-add", disabled: newItemCreationPending, children: newItemCreationPending ? "Adding\u2026" : "Add" })
|
|
2921
|
+
] }) : /* @__PURE__ */ jsx5("button", { type: "submit", className: "db-new-item-add", disabled: newItemCreationPending, children: newItemCreationPending ? "Adding\u2026" : "Add" })
|
|
2273
2922
|
]
|
|
2274
2923
|
}
|
|
2275
2924
|
),
|
|
@@ -2623,6 +3272,8 @@ function AppMenu({
|
|
|
2623
3272
|
onAccentColorChange,
|
|
2624
3273
|
writeCanvasSettings = DEFAULT_WRITE_CANVAS_PREFERENCES,
|
|
2625
3274
|
onWriteCanvasSettingsChange,
|
|
3275
|
+
proofingPreferences = DEFAULT_PROOFING_PREFERENCES,
|
|
3276
|
+
onProofingPreferencesChange,
|
|
2626
3277
|
versioningPreference = "browser-only",
|
|
2627
3278
|
onVersioningPreferenceChange,
|
|
2628
3279
|
onDownloadAllWorkspaces,
|
|
@@ -2797,6 +3448,13 @@ function AppMenu({
|
|
|
2797
3448
|
onChange: (settings) => onWriteCanvasSettingsChange?.(settings)
|
|
2798
3449
|
}
|
|
2799
3450
|
),
|
|
3451
|
+
/* @__PURE__ */ jsx7(
|
|
3452
|
+
ProofingSettingsControls,
|
|
3453
|
+
{
|
|
3454
|
+
value: proofingPreferences,
|
|
3455
|
+
onChange: (settings) => onProofingPreferencesChange?.(settings)
|
|
3456
|
+
}
|
|
3457
|
+
),
|
|
2800
3458
|
getStorageEstimate && /* @__PURE__ */ jsxs6("fieldset", { className: "db-settings-fieldset", children: [
|
|
2801
3459
|
/* @__PURE__ */ jsx7("legend", { className: "db-settings-legend", children: "Storage" }),
|
|
2802
3460
|
/* @__PURE__ */ jsx7("p", { className: "db-settings-hint", children: storageEstimate ? `DocBlocks documents and app data are using ${formatBytes(
|
|
@@ -3199,7 +3857,7 @@ function useDocumentSession(autoSaveDelayMs = 500) {
|
|
|
3199
3857
|
import { lazy, Suspense } from "react";
|
|
3200
3858
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
3201
3859
|
var ExportToolbarControlsImplementation = lazy(
|
|
3202
|
-
() => import("./ExportToolbarControls-
|
|
3860
|
+
() => import("./ExportToolbarControls-QYLBRWM7.js").then((module) => ({
|
|
3203
3861
|
default: module.ExportToolbarControls
|
|
3204
3862
|
}))
|
|
3205
3863
|
);
|
|
@@ -3322,27 +3980,39 @@ function useGit(provider, requestedWorkspaceId, theme) {
|
|
|
3322
3980
|
const available = gitApi !== null && capabilities?.gitAvailable === true;
|
|
3323
3981
|
const [repo, setRepo] = useState10(null);
|
|
3324
3982
|
const [remoteWeb, setRemoteWeb] = useState10(null);
|
|
3983
|
+
const [pendingGrant, setPendingGrant] = useState10(null);
|
|
3984
|
+
const loadRemote = useCallback9(
|
|
3985
|
+
(repositoryId2, isCancelled) => {
|
|
3986
|
+
if (!gitApi) return;
|
|
3987
|
+
void gitApi.listRemotes(repositoryId2).then(
|
|
3988
|
+
(remotes) => {
|
|
3989
|
+
if (isCancelled() || !remotes.ok) return;
|
|
3990
|
+
const first = remotes.value[0];
|
|
3991
|
+
setRemoteWeb(first?.web ?? null);
|
|
3992
|
+
},
|
|
3993
|
+
() => void 0
|
|
3994
|
+
);
|
|
3995
|
+
},
|
|
3996
|
+
[gitApi]
|
|
3997
|
+
);
|
|
3325
3998
|
useEffect9(() => {
|
|
3326
3999
|
setRepo(null);
|
|
3327
4000
|
setRemoteWeb(null);
|
|
4001
|
+
setPendingGrant(null);
|
|
3328
4002
|
if (!gitApi || !workspaceId || !available) return;
|
|
3329
4003
|
let cancelled = false;
|
|
4004
|
+
const isCancelled = () => cancelled;
|
|
3330
4005
|
void gitApi.detectRepo(workspaceId).then(
|
|
3331
4006
|
(result) => {
|
|
3332
|
-
if (cancelled || !result.ok || !result.value.isRepo
|
|
4007
|
+
if (cancelled || !result.ok || !result.value.isRepo) return;
|
|
4008
|
+
if (!result.value.repositoryId) {
|
|
4009
|
+
if (result.value.requiresExpandedGrant) {
|
|
4010
|
+
setPendingGrant({ repositoryRoot: result.value.repositoryRoot ?? null });
|
|
4011
|
+
}
|
|
3333
4012
|
return;
|
|
3334
4013
|
}
|
|
3335
4014
|
setRepo(result.value);
|
|
3336
|
-
|
|
3337
|
-
(remotes) => {
|
|
3338
|
-
if (cancelled || !remotes.ok) return;
|
|
3339
|
-
const first = remotes.value[0];
|
|
3340
|
-
setRemoteWeb(first?.web ?? null);
|
|
3341
|
-
},
|
|
3342
|
-
// No remote is a supported state; a failed probe degrades to it
|
|
3343
|
-
// rather than surfacing an unhandled rejection.
|
|
3344
|
-
() => void 0
|
|
3345
|
-
);
|
|
4015
|
+
loadRemote(result.value.repositoryId, isCancelled);
|
|
3346
4016
|
},
|
|
3347
4017
|
/* detection failure → not a repo, which is the default state */
|
|
3348
4018
|
() => void 0
|
|
@@ -3350,7 +4020,25 @@ function useGit(provider, requestedWorkspaceId, theme) {
|
|
|
3350
4020
|
return () => {
|
|
3351
4021
|
cancelled = true;
|
|
3352
4022
|
};
|
|
3353
|
-
}, [gitApi, workspaceId, available]);
|
|
4023
|
+
}, [gitApi, workspaceId, available, loadRemote]);
|
|
4024
|
+
const [grantBusy, setGrantBusy] = useState10(false);
|
|
4025
|
+
const enableExpandedRepo = useCallback9(
|
|
4026
|
+
async (opts) => {
|
|
4027
|
+
if (!gitApi || !workspaceId) return false;
|
|
4028
|
+
setGrantBusy(true);
|
|
4029
|
+
try {
|
|
4030
|
+
const result = await gitApi.grantExpandedRepo(workspaceId, opts);
|
|
4031
|
+
if (!result.ok || !result.value.repositoryId) return false;
|
|
4032
|
+
setRepo(result.value);
|
|
4033
|
+
setPendingGrant(null);
|
|
4034
|
+
loadRemote(result.value.repositoryId, () => false);
|
|
4035
|
+
return true;
|
|
4036
|
+
} finally {
|
|
4037
|
+
setGrantBusy(false);
|
|
4038
|
+
}
|
|
4039
|
+
},
|
|
4040
|
+
[gitApi, workspaceId, loadRemote]
|
|
4041
|
+
);
|
|
3354
4042
|
const repositoryId = repo?.repositoryId ?? null;
|
|
3355
4043
|
const isRepo = repositoryId !== null;
|
|
3356
4044
|
const { status, refresh, scheduleRefresh } = useGitStatus(gitApi, repositoryId, isRepo);
|
|
@@ -3499,6 +4187,9 @@ function useGit(provider, requestedWorkspaceId, theme) {
|
|
|
3499
4187
|
capabilities,
|
|
3500
4188
|
repo,
|
|
3501
4189
|
repositoryId,
|
|
4190
|
+
pendingGrant,
|
|
4191
|
+
grantBusy,
|
|
4192
|
+
enableExpandedRepo,
|
|
3502
4193
|
remoteWeb,
|
|
3503
4194
|
gitApi,
|
|
3504
4195
|
provider,
|
|
@@ -3526,6 +4217,9 @@ function useGit(provider, requestedWorkspaceId, theme) {
|
|
|
3526
4217
|
capabilities,
|
|
3527
4218
|
repo,
|
|
3528
4219
|
repositoryId,
|
|
4220
|
+
pendingGrant,
|
|
4221
|
+
grantBusy,
|
|
4222
|
+
enableExpandedRepo,
|
|
3529
4223
|
remoteWeb,
|
|
3530
4224
|
gitApi,
|
|
3531
4225
|
provider,
|
|
@@ -3717,158 +4411,10 @@ function hasControlCharacter(value) {
|
|
|
3717
4411
|
|
|
3718
4412
|
// src/DocBlocksShell/import-files.ts
|
|
3719
4413
|
import {
|
|
3720
|
-
FsError as
|
|
3721
|
-
getFileSystemProviderV2 as
|
|
3722
|
-
parseWorkspacePath as
|
|
3723
|
-
} from "@bendyline/docblocks/filesystem";
|
|
3724
|
-
|
|
3725
|
-
// src/DocBlocksShell/outside-in-contract.ts
|
|
3726
|
-
var OUTSIDE_IN_FORMAT_IDS = ["html", "docx", "pdf", "pptx", "xlsx"];
|
|
3727
|
-
var FORMAT_IDS = new Set(OUTSIDE_IN_FORMAT_IDS);
|
|
3728
|
-
var UPDATE_FROM_MARKDOWN_KEY = "squisq-updatefrommarkdown";
|
|
3729
|
-
function normalizePath(path) {
|
|
3730
|
-
const leading = path.replace(/\\/g, "/").startsWith("/") ? "/" : "";
|
|
3731
|
-
const parts = path.replace(/\\/g, "/").split("/").filter(Boolean);
|
|
3732
|
-
if (parts.some((part) => part === "." || part === "..")) {
|
|
3733
|
-
throw new Error(`Outside-in paths must be canonical workspace paths: ${path}`);
|
|
3734
|
-
}
|
|
3735
|
-
return leading + parts.join("/");
|
|
3736
|
-
}
|
|
3737
|
-
function join(parent, child) {
|
|
3738
|
-
if (!parent || parent === "/") return parent === "/" ? `/${child}` : child;
|
|
3739
|
-
return `${parent}/${child}`;
|
|
3740
|
-
}
|
|
3741
|
-
function slug(stem) {
|
|
3742
|
-
return stem.normalize("NFKD").replace(/\p{Mark}+/gu, "").toLocaleLowerCase("en-US").replace(/[^\p{Letter}\p{Number}]+/gu, "-").replace(/^-+|-+$/g, "") || "document";
|
|
3743
|
-
}
|
|
3744
|
-
function resolveOutsideInLayout(path) {
|
|
3745
|
-
const targetPath = normalizePath(path);
|
|
3746
|
-
const slash = targetPath.lastIndexOf("/");
|
|
3747
|
-
const parentDirectory = slash < 0 ? "" : slash === 0 ? "/" : targetPath.slice(0, slash);
|
|
3748
|
-
const filename = slash < 0 ? targetPath : targetPath.slice(slash + 1);
|
|
3749
|
-
const dot = filename.lastIndexOf(".");
|
|
3750
|
-
if (dot <= 0) return null;
|
|
3751
|
-
const rawFormat = filename.slice(dot + 1).toLowerCase();
|
|
3752
|
-
const format = rawFormat === "htm" ? "html" : rawFormat;
|
|
3753
|
-
if (!FORMAT_IDS.has(format)) return null;
|
|
3754
|
-
const stem = filename.slice(0, dot);
|
|
3755
|
-
const companionName = `${stem}_files`;
|
|
3756
|
-
const companionDirectory = join(parentDirectory, companionName);
|
|
3757
|
-
const markdownFilename = `${slug(stem)}.md`;
|
|
3758
|
-
const backupDirectory = join(companionDirectory, ".original");
|
|
3759
|
-
const backupFilename = `original.${format}`;
|
|
3760
|
-
return {
|
|
3761
|
-
targetPath,
|
|
3762
|
-
format,
|
|
3763
|
-
parentDirectory,
|
|
3764
|
-
stem,
|
|
3765
|
-
companionName,
|
|
3766
|
-
companionDirectory,
|
|
3767
|
-
markdownFilename,
|
|
3768
|
-
markdownPath: join(companionDirectory, markdownFilename),
|
|
3769
|
-
relativeTargetPath: `../${filename}`,
|
|
3770
|
-
backupDirectory,
|
|
3771
|
-
backupFilename,
|
|
3772
|
-
backupPath: join(backupDirectory, backupFilename)
|
|
3773
|
-
};
|
|
3774
|
-
}
|
|
3775
|
-
function chooseOutsideInMarkdownPath(layout, paths) {
|
|
3776
|
-
const canonical = normalizePath(layout.markdownPath);
|
|
3777
|
-
const normalized = paths.map(normalizePath);
|
|
3778
|
-
const exact = normalized.find((path) => path === canonical);
|
|
3779
|
-
if (exact) return exact;
|
|
3780
|
-
const folded = normalized.find(
|
|
3781
|
-
(path) => path.toLocaleLowerCase("en-US") === canonical.toLocaleLowerCase("en-US")
|
|
3782
|
-
);
|
|
3783
|
-
if (folded) return folded;
|
|
3784
|
-
const prefix = `${normalizePath(layout.companionDirectory).replace(/\/$/, "")}/`;
|
|
3785
|
-
const markdown = normalized.filter(
|
|
3786
|
-
(path) => path.startsWith(prefix) && !path.slice(prefix.length).includes("/") && path.toLocaleLowerCase("en-US").endsWith(".md")
|
|
3787
|
-
);
|
|
3788
|
-
return markdown.length === 1 ? markdown[0] : null;
|
|
3789
|
-
}
|
|
3790
|
-
async function readOutsideInMetadata(source) {
|
|
3791
|
-
const { readOutsideInMetadata: readMetadata } = await import("@bendyline/squisq-formats/outside-in");
|
|
3792
|
-
const metadata = readMetadata(source);
|
|
3793
|
-
return metadata ? {
|
|
3794
|
-
...metadata,
|
|
3795
|
-
updateFromMarkdown: await isOutsideInMarkdownEditingEnabled(source)
|
|
3796
|
-
} : null;
|
|
3797
|
-
}
|
|
3798
|
-
async function withOutsideInMetadata(source, layout) {
|
|
3799
|
-
const { withOutsideInMetadata: addMetadata } = await import("@bendyline/squisq-formats/outside-in");
|
|
3800
|
-
return addMetadata(source, layout);
|
|
3801
|
-
}
|
|
3802
|
-
async function isOutsideInMarkdownEditingEnabled(source) {
|
|
3803
|
-
const module = await import("@bendyline/squisq-formats/outside-in");
|
|
3804
|
-
if (module.isOutsideInMarkdownEditingEnabled) {
|
|
3805
|
-
return module.isOutsideInMarkdownEditingEnabled(source);
|
|
3806
|
-
}
|
|
3807
|
-
const { parseFrontmatter, splitFrontmatterBlock } = await import("@bendyline/squisq/markdown");
|
|
3808
|
-
const block = splitFrontmatterBlock(source).frontmatter;
|
|
3809
|
-
if (!block) return false;
|
|
3810
|
-
const firstBreak = block.indexOf("\n");
|
|
3811
|
-
if (firstBreak < 0) return false;
|
|
3812
|
-
const yaml = block.slice(firstBreak + 1).replace(/\r?\n---(?:\r?\n)?$/, "");
|
|
3813
|
-
return parseFrontmatter(yaml)?.[UPDATE_FROM_MARKDOWN_KEY] === true;
|
|
3814
|
-
}
|
|
3815
|
-
async function withOutsideInMarkdownEditing(source, layout, enabled = true) {
|
|
3816
|
-
const module = await import("@bendyline/squisq-formats/outside-in");
|
|
3817
|
-
if (module.withOutsideInMarkdownEditing) {
|
|
3818
|
-
return module.withOutsideInMarkdownEditing(source, layout, enabled);
|
|
3819
|
-
}
|
|
3820
|
-
const { setFrontmatterValues } = await import("@bendyline/squisq/markdown");
|
|
3821
|
-
return setFrontmatterValues(await withOutsideInMetadata(source, layout), {
|
|
3822
|
-
[UPDATE_FROM_MARKDOWN_KEY]: enabled
|
|
3823
|
-
});
|
|
3824
|
-
}
|
|
3825
|
-
async function importOutsideInDocument(source, options = {}) {
|
|
3826
|
-
const { importOutsideInDocument: importDocument } = await import("@bendyline/squisq-formats/outside-in");
|
|
3827
|
-
const imported = await importDocument(source, options);
|
|
3828
|
-
const layout = resolveOutsideInLayout(source.targetPath);
|
|
3829
|
-
if (!layout) throw new Error(`Outside-in editing does not support "${source.targetPath}".`);
|
|
3830
|
-
return { ...imported, layout };
|
|
3831
|
-
}
|
|
3832
|
-
async function renderOutsideInDocument(source, options = {}) {
|
|
3833
|
-
const { renderOutsideInDocument: renderDocument } = await import("@bendyline/squisq-formats/outside-in");
|
|
3834
|
-
return renderDocument(source, options);
|
|
3835
|
-
}
|
|
3836
|
-
|
|
3837
|
-
// src/DocBlocksShell/provider-io.ts
|
|
3838
|
-
import {
|
|
3839
|
-
FsError as FsError2,
|
|
3840
|
-
getFileSystemProviderV2 as getFileSystemProviderV22,
|
|
3841
|
-
parseWorkspacePath as parseWorkspacePath3
|
|
4414
|
+
FsError as FsError4,
|
|
4415
|
+
getFileSystemProviderV2 as getFileSystemProviderV24,
|
|
4416
|
+
parseWorkspacePath as parseWorkspacePath5
|
|
3842
4417
|
} from "@bendyline/docblocks/filesystem";
|
|
3843
|
-
async function providerEntryExists(provider, path) {
|
|
3844
|
-
const providerV2 = getFileSystemProviderV22(provider);
|
|
3845
|
-
return providerV2 ? await providerV2.stat(parseWorkspacePath3(path)) !== null : provider.exists(path);
|
|
3846
|
-
}
|
|
3847
|
-
async function writeProviderText(provider, path, content, mode = "upsert") {
|
|
3848
|
-
const providerV2 = getFileSystemProviderV22(provider);
|
|
3849
|
-
if (providerV2) {
|
|
3850
|
-
await providerV2.writeFile(parseWorkspacePath3(path), new TextEncoder().encode(content), {
|
|
3851
|
-
mode,
|
|
3852
|
-
createParents: true,
|
|
3853
|
-
expectedVersion: mode === "create" ? null : void 0
|
|
3854
|
-
});
|
|
3855
|
-
return;
|
|
3856
|
-
}
|
|
3857
|
-
if (mode === "create" && await provider.exists(path)) {
|
|
3858
|
-
throw new FsError2("already-exists", "File already exists.", { operation: "write", path });
|
|
3859
|
-
}
|
|
3860
|
-
await provider.writeFile(path, content);
|
|
3861
|
-
}
|
|
3862
|
-
async function removeProviderEntry(provider, path) {
|
|
3863
|
-
const providerV2 = getFileSystemProviderV22(provider);
|
|
3864
|
-
if (providerV2) {
|
|
3865
|
-
await providerV2.remove(parseWorkspacePath3(path), { recursive: true, missing: "ignore" });
|
|
3866
|
-
return;
|
|
3867
|
-
}
|
|
3868
|
-
await provider.delete(path);
|
|
3869
|
-
}
|
|
3870
|
-
|
|
3871
|
-
// src/DocBlocksShell/import-files.ts
|
|
3872
4418
|
var MAX_NAME_ATTEMPTS = 100;
|
|
3873
4419
|
function withCopySuffix(path, n) {
|
|
3874
4420
|
const dot = path.lastIndexOf(".");
|
|
@@ -3877,7 +4423,7 @@ function withCopySuffix(path, n) {
|
|
|
3877
4423
|
return `${path.slice(0, dot)} (${n})${path.slice(dot)}`;
|
|
3878
4424
|
}
|
|
3879
4425
|
function isAlreadyExists(error) {
|
|
3880
|
-
return error instanceof
|
|
4426
|
+
return error instanceof FsError4 && error.code === "already-exists";
|
|
3881
4427
|
}
|
|
3882
4428
|
async function claimAvailablePath(provider, desiredPath) {
|
|
3883
4429
|
for (let attempt = 1; attempt <= MAX_NAME_ATTEMPTS; attempt++) {
|
|
@@ -3892,9 +4438,9 @@ async function claimAvailablePath(provider, desiredPath) {
|
|
|
3892
4438
|
throw new Error(`Too many documents are already named like \u201C${desiredPath}\u201D.`);
|
|
3893
4439
|
}
|
|
3894
4440
|
async function writeProviderBytes(provider, path, data, mode) {
|
|
3895
|
-
const providerV2 =
|
|
4441
|
+
const providerV2 = getFileSystemProviderV24(provider);
|
|
3896
4442
|
if (providerV2) {
|
|
3897
|
-
await providerV2.writeFile(
|
|
4443
|
+
await providerV2.writeFile(parseWorkspacePath5(path), data, {
|
|
3898
4444
|
mode,
|
|
3899
4445
|
createParents: true,
|
|
3900
4446
|
expectedVersion: mode === "create" ? null : void 0
|
|
@@ -3902,11 +4448,10 @@ async function writeProviderBytes(provider, path, data, mode) {
|
|
|
3902
4448
|
return;
|
|
3903
4449
|
}
|
|
3904
4450
|
if (mode === "create" && await providerEntryExists(provider, path)) {
|
|
3905
|
-
throw new
|
|
4451
|
+
throw new FsError4("already-exists", "File already exists.", { operation: "write", path });
|
|
3906
4452
|
}
|
|
3907
4453
|
await provider.writeBinary(path, data);
|
|
3908
4454
|
}
|
|
3909
|
-
var OUTSIDE_IN_EXTENSIONS = /* @__PURE__ */ new Set([".html", ".htm", ".docx", ".pdf", ".pptx", ".xlsx"]);
|
|
3910
4455
|
async function claimOutsideInTarget(provider, desiredPath) {
|
|
3911
4456
|
for (let attempt = 1; attempt <= MAX_NAME_ATTEMPTS; attempt++) {
|
|
3912
4457
|
const candidate = attempt === 1 ? desiredPath : withCopySuffix(desiredPath, attempt);
|
|
@@ -3950,10 +4495,7 @@ async function importOutsideInFile(file, provider) {
|
|
|
3950
4495
|
throw error;
|
|
3951
4496
|
}
|
|
3952
4497
|
}
|
|
3953
|
-
async function readImportedMarkdown(file,
|
|
3954
|
-
if (ext === ".md" || ext === ".txt") {
|
|
3955
|
-
return file.text();
|
|
3956
|
-
}
|
|
4498
|
+
async function readImportedMarkdown(file, destPath, provider) {
|
|
3957
4499
|
const snapshot = await decodeDbkWorkspace(await file.arrayBuffer(), {
|
|
3958
4500
|
targetDocumentPath: destPath
|
|
3959
4501
|
});
|
|
@@ -3967,27 +4509,31 @@ async function writeDbkCompanions(snapshot, provider) {
|
|
|
3967
4509
|
await writeProviderText(provider, entry.path, entry.content, "create");
|
|
3968
4510
|
}
|
|
3969
4511
|
}
|
|
3970
|
-
var SUPPORTED_EXTENSIONS2 = /* @__PURE__ */ new Set([".md", ".txt", ...OUTSIDE_IN_EXTENSIONS, ".dbk", ".zip"]);
|
|
3971
4512
|
async function importDroppedFiles(files, provider) {
|
|
3972
4513
|
const result = { imported: [], failed: [], unsupported: [] };
|
|
3973
4514
|
for (const file of files) {
|
|
3974
|
-
const ext =
|
|
3975
|
-
if (!
|
|
4515
|
+
const ext = extensionOfFileName(file.name);
|
|
4516
|
+
if (!isSupportedImportFile(file)) {
|
|
3976
4517
|
result.unsupported.push(file.name);
|
|
3977
4518
|
continue;
|
|
3978
4519
|
}
|
|
3979
|
-
const baseName = file.name.replace(/\.[^.]+$/, "");
|
|
3980
4520
|
let claimed = null;
|
|
3981
4521
|
try {
|
|
3982
|
-
if (
|
|
4522
|
+
if (OUTSIDE_IN_IMPORT_EXTENSIONS.has(ext)) {
|
|
3983
4523
|
const imported = await importOutsideInFile(file, provider);
|
|
3984
4524
|
result.imported.push({ source: file.name, ...imported });
|
|
3985
4525
|
continue;
|
|
3986
4526
|
}
|
|
3987
|
-
const
|
|
4527
|
+
const isBundle = BUNDLE_IMPORT_EXTENSIONS.has(ext);
|
|
4528
|
+
const desiredPath = isBundle ? `${file.name.replace(/\.[^.]+$/, "")}.md` : file.name;
|
|
4529
|
+
const claim = await claimAvailablePath(provider, desiredPath);
|
|
3988
4530
|
claimed = claim.path;
|
|
3989
|
-
|
|
3990
|
-
|
|
4531
|
+
if (isBundle) {
|
|
4532
|
+
const markdown = await readImportedMarkdown(file, claim.path, provider);
|
|
4533
|
+
await writeProviderText(provider, claim.path, markdown);
|
|
4534
|
+
} else {
|
|
4535
|
+
await writeProviderBytes(provider, claim.path, await file.arrayBuffer(), "upsert");
|
|
4536
|
+
}
|
|
3991
4537
|
result.imported.push({ source: file.name, path: claim.path, renamed: claim.renamed });
|
|
3992
4538
|
} catch (error) {
|
|
3993
4539
|
if (claimed) {
|
|
@@ -4003,16 +4549,13 @@ async function importDroppedFiles(files, provider) {
|
|
|
4003
4549
|
}
|
|
4004
4550
|
function summariseImport(result) {
|
|
4005
4551
|
const { imported, failed, unsupported } = result;
|
|
4006
|
-
|
|
4007
|
-
|
|
4552
|
+
const rejectedCount = failed.length + unsupported.length;
|
|
4553
|
+
if (rejectedCount > 0) {
|
|
4554
|
+
const detail = failed.length === 1 && unsupported.length === 0 ? `Could not import ${failed[0].source} \u2014 ${failed[0].message}` : unsupported.length === 1 && failed.length === 0 ? `${unsupported[0]} is not a file type DocBlocks can import.` : `Could not import ${rejectedCount} of ${rejectedCount + imported.length} files.`;
|
|
4008
4555
|
return { kind: "error", message: detail };
|
|
4009
4556
|
}
|
|
4010
4557
|
if (imported.length === 0) {
|
|
4011
|
-
|
|
4012
|
-
return {
|
|
4013
|
-
kind: "error",
|
|
4014
|
-
message: unsupported.length === 1 ? `${unsupported[0]} is not a file type DocBlocks can import.` : `${unsupported.length} dropped files are not file types DocBlocks can import.`
|
|
4015
|
-
};
|
|
4558
|
+
return null;
|
|
4016
4559
|
}
|
|
4017
4560
|
const renamed = imported.filter((entry) => entry.renamed);
|
|
4018
4561
|
if (renamed.length === 1) {
|
|
@@ -4030,241 +4573,6 @@ function summariseImport(result) {
|
|
|
4030
4573
|
return null;
|
|
4031
4574
|
}
|
|
4032
4575
|
|
|
4033
|
-
// src/DocBlocksShell/outside-in.ts
|
|
4034
|
-
import {
|
|
4035
|
-
FileSystemContentContainer,
|
|
4036
|
-
FsError as FsError4,
|
|
4037
|
-
getFileSystemProviderV2 as getFileSystemProviderV24,
|
|
4038
|
-
parseWorkspacePath as parseWorkspacePath5
|
|
4039
|
-
} from "@bendyline/docblocks/filesystem";
|
|
4040
|
-
import {
|
|
4041
|
-
createFileSystemDocumentTarget
|
|
4042
|
-
} from "@bendyline/docblocks/document";
|
|
4043
|
-
var OUTSIDE_IN_EXTENSION = /\.(?:html?|docx|pdf|pptx|xlsx)$/i;
|
|
4044
|
-
var SQUISQ_RUNTIME_DIRECTORY = "_squisq";
|
|
4045
|
-
var SQUISQ_RUNTIME_FILENAME = "squisq-player.js";
|
|
4046
|
-
function withoutLeadingSlash(path) {
|
|
4047
|
-
return parseWorkspacePath5(path);
|
|
4048
|
-
}
|
|
4049
|
-
function withLegacySlash(path, like) {
|
|
4050
|
-
const canonical = withoutLeadingSlash(path);
|
|
4051
|
-
return like.startsWith("/") && canonical ? `/${canonical}` : canonical;
|
|
4052
|
-
}
|
|
4053
|
-
function dirname(path) {
|
|
4054
|
-
const canonical = withoutLeadingSlash(path);
|
|
4055
|
-
const slash = canonical.lastIndexOf("/");
|
|
4056
|
-
return slash < 0 ? "" : canonical.slice(0, slash);
|
|
4057
|
-
}
|
|
4058
|
-
function join2(parent, child) {
|
|
4059
|
-
return parent ? `${parent}/${child}` : child;
|
|
4060
|
-
}
|
|
4061
|
-
function relativePath(fromDirectory, targetPath) {
|
|
4062
|
-
const from = withoutLeadingSlash(fromDirectory).split("/").filter(Boolean);
|
|
4063
|
-
const target = withoutLeadingSlash(targetPath).split("/").filter(Boolean);
|
|
4064
|
-
let shared = 0;
|
|
4065
|
-
while (shared < from.length && shared < target.length && from[shared] === target[shared]) {
|
|
4066
|
-
shared++;
|
|
4067
|
-
}
|
|
4068
|
-
const segments = [...from.slice(shared).map(() => ".."), ...target.slice(shared)];
|
|
4069
|
-
return segments.join("/") || ".";
|
|
4070
|
-
}
|
|
4071
|
-
async function readText(provider, path) {
|
|
4072
|
-
const v2 = getFileSystemProviderV24(provider);
|
|
4073
|
-
if (!v2) return provider.readFile(path);
|
|
4074
|
-
const current = await v2.readFile(parseWorkspacePath5(path));
|
|
4075
|
-
if (!current) return null;
|
|
4076
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(current.data);
|
|
4077
|
-
}
|
|
4078
|
-
async function readBytes(provider, path) {
|
|
4079
|
-
const v2 = getFileSystemProviderV24(provider);
|
|
4080
|
-
if (v2) return (await v2.readFile(parseWorkspacePath5(path)))?.data ?? null;
|
|
4081
|
-
return provider.readBinary(path);
|
|
4082
|
-
}
|
|
4083
|
-
async function writeBytes(provider, path, data, mode = "upsert") {
|
|
4084
|
-
const v2 = getFileSystemProviderV24(provider);
|
|
4085
|
-
if (v2) {
|
|
4086
|
-
await v2.writeFile(parseWorkspacePath5(path), data, {
|
|
4087
|
-
mode,
|
|
4088
|
-
createParents: true,
|
|
4089
|
-
expectedVersion: mode === "create" ? null : void 0
|
|
4090
|
-
});
|
|
4091
|
-
return;
|
|
4092
|
-
}
|
|
4093
|
-
if (mode === "create" && await provider.exists(path)) {
|
|
4094
|
-
throw new FsError4("already-exists", "File already exists.", { operation: "write", path });
|
|
4095
|
-
}
|
|
4096
|
-
await provider.writeBinary(path, data);
|
|
4097
|
-
}
|
|
4098
|
-
async function listCompanionFiles(provider, layout) {
|
|
4099
|
-
try {
|
|
4100
|
-
const entries = await provider.readDirectory(layout.companionDirectory);
|
|
4101
|
-
return entries.filter((entry) => entry.kind === "file").map((entry) => entry.path);
|
|
4102
|
-
} catch (error) {
|
|
4103
|
-
if (error instanceof FsError4 && error.code === "not-found") return [];
|
|
4104
|
-
throw error;
|
|
4105
|
-
}
|
|
4106
|
-
}
|
|
4107
|
-
async function removeOutsideInCompanion(provider, layout) {
|
|
4108
|
-
const providerV2 = getFileSystemProviderV24(provider);
|
|
4109
|
-
if (providerV2) {
|
|
4110
|
-
const path = parseWorkspacePath5(layout.companionDirectory);
|
|
4111
|
-
if (await providerV2.stat(path) !== null) {
|
|
4112
|
-
await providerV2.remove(path, { recursive: true, missing: "ignore" });
|
|
4113
|
-
}
|
|
4114
|
-
return;
|
|
4115
|
-
}
|
|
4116
|
-
if (await provider.exists(layout.companionDirectory)) {
|
|
4117
|
-
await provider.delete(layout.companionDirectory);
|
|
4118
|
-
}
|
|
4119
|
-
}
|
|
4120
|
-
async function persistImportedMedia(provider, layout, container) {
|
|
4121
|
-
const entries = await container.listFiles();
|
|
4122
|
-
for (const entry of entries) {
|
|
4123
|
-
if (/\.md$/i.test(entry.path)) continue;
|
|
4124
|
-
const data = await container.readFile(entry.path);
|
|
4125
|
-
if (!data) continue;
|
|
4126
|
-
await writeBytes(provider, join2(layout.companionDirectory, entry.path), data, "create");
|
|
4127
|
-
}
|
|
4128
|
-
}
|
|
4129
|
-
async function loadEditableShellDocument(provider, selectedPath) {
|
|
4130
|
-
if (!OUTSIDE_IN_EXTENSION.test(selectedPath)) {
|
|
4131
|
-
const content = await readText(provider, selectedPath);
|
|
4132
|
-
return content === null ? null : {
|
|
4133
|
-
displayPath: selectedPath,
|
|
4134
|
-
sourcePath: selectedPath,
|
|
4135
|
-
content,
|
|
4136
|
-
outsideIn: null,
|
|
4137
|
-
outsideInEditingEnabled: true
|
|
4138
|
-
};
|
|
4139
|
-
}
|
|
4140
|
-
const resolved = resolveOutsideInLayout(selectedPath);
|
|
4141
|
-
if (!resolved) return null;
|
|
4142
|
-
const layout = {
|
|
4143
|
-
...resolved,
|
|
4144
|
-
targetPath: withLegacySlash(resolved.targetPath, selectedPath),
|
|
4145
|
-
companionDirectory: withLegacySlash(resolved.companionDirectory, selectedPath),
|
|
4146
|
-
markdownPath: withLegacySlash(resolved.markdownPath, selectedPath)
|
|
4147
|
-
};
|
|
4148
|
-
const candidates = (await listCompanionFiles(provider, layout)).map(
|
|
4149
|
-
(path) => withLegacySlash(path, selectedPath)
|
|
4150
|
-
);
|
|
4151
|
-
const chosen = chooseOutsideInMarkdownPath(layout, candidates);
|
|
4152
|
-
if (chosen) {
|
|
4153
|
-
const content = await readText(provider, chosen);
|
|
4154
|
-
if (content === null) return null;
|
|
4155
|
-
const metadata = await readOutsideInMetadata(content);
|
|
4156
|
-
if (metadata && metadata.format !== layout.format) {
|
|
4157
|
-
throw new Error(
|
|
4158
|
-
`${chosen} is configured for ${metadata.format}, not ${layout.format}. Rename the rendered file back or repair the companion frontmatter.`
|
|
4159
|
-
);
|
|
4160
|
-
}
|
|
4161
|
-
const linkedContent = await withOutsideInMetadata(content, layout);
|
|
4162
|
-
if (linkedContent !== content) await writeProviderText(provider, chosen, linkedContent);
|
|
4163
|
-
return {
|
|
4164
|
-
displayPath: selectedPath,
|
|
4165
|
-
sourcePath: chosen,
|
|
4166
|
-
content: linkedContent,
|
|
4167
|
-
outsideIn: { ...layout, markdownPath: chosen },
|
|
4168
|
-
outsideInEditingEnabled: await isOutsideInMarkdownEditingEnabled(linkedContent)
|
|
4169
|
-
};
|
|
4170
|
-
}
|
|
4171
|
-
const rendered = await readBytes(provider, selectedPath);
|
|
4172
|
-
if (!rendered) return null;
|
|
4173
|
-
const imported = await importOutsideInDocument({
|
|
4174
|
-
data: rendered,
|
|
4175
|
-
targetPath: selectedPath
|
|
4176
|
-
});
|
|
4177
|
-
const importedLayout = {
|
|
4178
|
-
...imported.layout,
|
|
4179
|
-
targetPath: withLegacySlash(imported.layout.targetPath, selectedPath),
|
|
4180
|
-
companionDirectory: withLegacySlash(imported.layout.companionDirectory, selectedPath),
|
|
4181
|
-
markdownPath: withLegacySlash(imported.layout.markdownPath, selectedPath)
|
|
4182
|
-
};
|
|
4183
|
-
await persistImportedMedia(provider, importedLayout, imported.container);
|
|
4184
|
-
await writeProviderText(provider, importedLayout.markdownPath, imported.markdown, "create");
|
|
4185
|
-
return {
|
|
4186
|
-
displayPath: selectedPath,
|
|
4187
|
-
sourcePath: importedLayout.markdownPath,
|
|
4188
|
-
content: imported.markdown,
|
|
4189
|
-
outsideIn: importedLayout,
|
|
4190
|
-
outsideInEditingEnabled: false
|
|
4191
|
-
};
|
|
4192
|
-
}
|
|
4193
|
-
async function enableOutsideInMarkdownEditing(provider, document2) {
|
|
4194
|
-
const layout = document2.outsideIn;
|
|
4195
|
-
if (!layout) throw new Error("This file does not support outside-in Markdown editing.");
|
|
4196
|
-
const original = await readBytes(provider, layout.targetPath);
|
|
4197
|
-
if (!original) throw new Error(`The rendered file "${layout.targetPath}" was not found.`);
|
|
4198
|
-
try {
|
|
4199
|
-
await writeBytes(provider, layout.backupPath, original, "create");
|
|
4200
|
-
} catch (error) {
|
|
4201
|
-
if (!(error instanceof FsError4 && error.code === "already-exists")) throw error;
|
|
4202
|
-
}
|
|
4203
|
-
const content = await withOutsideInMarkdownEditing(document2.content, layout);
|
|
4204
|
-
if (content !== document2.content) await writeProviderText(provider, document2.sourcePath, content);
|
|
4205
|
-
return { ...document2, content, outsideIn: layout, outsideInEditingEnabled: true };
|
|
4206
|
-
}
|
|
4207
|
-
async function findRuntimePath(provider, targetPath) {
|
|
4208
|
-
let directory = dirname(targetPath);
|
|
4209
|
-
for (; ; ) {
|
|
4210
|
-
const candidateDirectory = join2(directory, SQUISQ_RUNTIME_DIRECTORY);
|
|
4211
|
-
if (await providerEntryExists(provider, candidateDirectory)) {
|
|
4212
|
-
const providerV2 = getFileSystemProviderV24(provider);
|
|
4213
|
-
if (providerV2) {
|
|
4214
|
-
const entry = await providerV2.stat(parseWorkspacePath5(candidateDirectory));
|
|
4215
|
-
if (entry?.kind !== "directory") {
|
|
4216
|
-
throw new Error(`${candidateDirectory} must be a directory.`);
|
|
4217
|
-
}
|
|
4218
|
-
}
|
|
4219
|
-
return join2(candidateDirectory, SQUISQ_RUNTIME_FILENAME);
|
|
4220
|
-
}
|
|
4221
|
-
if (!directory) break;
|
|
4222
|
-
directory = dirname(directory);
|
|
4223
|
-
}
|
|
4224
|
-
return join2(SQUISQ_RUNTIME_DIRECTORY, SQUISQ_RUNTIME_FILENAME);
|
|
4225
|
-
}
|
|
4226
|
-
async function writeRuntimeIfNeeded(provider, runtimePath) {
|
|
4227
|
-
const { PLAYER_BUNDLE } = await import("@bendyline/squisq-react/standalone-source");
|
|
4228
|
-
const current = await readText(provider, runtimePath);
|
|
4229
|
-
if (current !== PLAYER_BUNDLE) await writeProviderText(provider, runtimePath, PLAYER_BUNDLE);
|
|
4230
|
-
}
|
|
4231
|
-
function createOutsideInDocumentTarget(provider, layout, onCommitted) {
|
|
4232
|
-
const sourceTarget = createFileSystemDocumentTarget(provider, layout.markdownPath);
|
|
4233
|
-
return {
|
|
4234
|
-
key: `${provider.id}:outside-in:${parseWorkspacePath5(layout.targetPath)}`,
|
|
4235
|
-
async commit(request) {
|
|
4236
|
-
if (!await isOutsideInMarkdownEditingEnabled(request.content)) {
|
|
4237
|
-
throw new Error(
|
|
4238
|
-
"Outside-in editing is read-only until squisq-updatefrommarkdown: true is set."
|
|
4239
|
-
);
|
|
4240
|
-
}
|
|
4241
|
-
const runtimePath = layout.format === "html" ? await findRuntimePath(provider, layout.targetPath) : null;
|
|
4242
|
-
const outputDirectory = dirname(layout.targetPath);
|
|
4243
|
-
const rendered = await renderOutsideInDocument(
|
|
4244
|
-
{
|
|
4245
|
-
markdown: request.content,
|
|
4246
|
-
targetPath: layout.targetPath,
|
|
4247
|
-
container: new FileSystemContentContainer(provider, layout.companionDirectory)
|
|
4248
|
-
},
|
|
4249
|
-
runtimePath ? {
|
|
4250
|
-
html: {
|
|
4251
|
-
playerScriptPath: relativePath(outputDirectory, runtimePath),
|
|
4252
|
-
basePath: relativePath(outputDirectory, layout.companionDirectory)
|
|
4253
|
-
}
|
|
4254
|
-
} : {}
|
|
4255
|
-
);
|
|
4256
|
-
await sourceTarget.commit({ ...request, targetKey: sourceTarget.key });
|
|
4257
|
-
if (runtimePath) await writeRuntimeIfNeeded(provider, runtimePath);
|
|
4258
|
-
await writeBytes(provider, layout.targetPath, rendered.bytes);
|
|
4259
|
-
onCommitted?.();
|
|
4260
|
-
return {};
|
|
4261
|
-
}
|
|
4262
|
-
};
|
|
4263
|
-
}
|
|
4264
|
-
function createOutsideInContentContainer(provider, layout) {
|
|
4265
|
-
return new FileSystemContentContainer(provider, layout.companionDirectory);
|
|
4266
|
-
}
|
|
4267
|
-
|
|
4268
4576
|
// src/components/usePromptDialog.ts
|
|
4269
4577
|
import React2, { useCallback as useCallback11, useEffect as useEffect12, useRef as useRef11, useState as useState12 } from "react";
|
|
4270
4578
|
|
|
@@ -4980,6 +5288,21 @@ async function copyTransientWorkspaceContents(source, destination) {
|
|
|
4980
5288
|
}
|
|
4981
5289
|
}
|
|
4982
5290
|
|
|
5291
|
+
// src/DocBlocksShell/native-file-actions.ts
|
|
5292
|
+
function createNativeFileActions(entry, workspaceId, host) {
|
|
5293
|
+
if (entry.kind !== "file" || workspaceId === null || host === null) return [];
|
|
5294
|
+
return [
|
|
5295
|
+
{
|
|
5296
|
+
label: "Open containing folder",
|
|
5297
|
+
onSelect: () => host.shell.revealInFolder(workspaceId, entry.path)
|
|
5298
|
+
},
|
|
5299
|
+
{
|
|
5300
|
+
label: "Copy full path",
|
|
5301
|
+
onSelect: () => host.clipboard.writeWorkspacePath(workspaceId, entry.path)
|
|
5302
|
+
}
|
|
5303
|
+
];
|
|
5304
|
+
}
|
|
5305
|
+
|
|
4983
5306
|
// src/DocBlocksShell/welcome-document.ts
|
|
4984
5307
|
var WELCOME_DOCUMENT_PATH = "/aboutDocBlocks.md";
|
|
4985
5308
|
var WELCOME_DOCUMENT_CONTENT = [
|
|
@@ -5078,9 +5401,12 @@ function loadEditorShell() {
|
|
|
5078
5401
|
return editorShellModulePromise;
|
|
5079
5402
|
}
|
|
5080
5403
|
var EditorShell = lazy2(loadEditorShell);
|
|
5081
|
-
var GitUI = lazy2(() => import("./GitUI-
|
|
5404
|
+
var GitUI = lazy2(() => import("./GitUI-L5T3XHZG.js").then((m) => ({ default: m.GitUI })));
|
|
5405
|
+
var GitGrantNotice = lazy2(
|
|
5406
|
+
() => import("./GitGrantNotice-I2VNKPLH.js").then((m) => ({ default: m.GitGrantNotice }))
|
|
5407
|
+
);
|
|
5082
5408
|
var GitToolbarControl = lazy2(
|
|
5083
|
-
() => import("./GitToolbarControl-
|
|
5409
|
+
() => import("./GitToolbarControl-O5AXBC6T.js").then((m) => ({ default: m.GitToolbarControl }))
|
|
5084
5410
|
);
|
|
5085
5411
|
var DOCBLOCKS_VIDEO_EXPORT_PALETTE = Object.freeze({
|
|
5086
5412
|
overlay: "rgba(0, 0, 0, 0.72)",
|
|
@@ -5351,6 +5677,8 @@ function useIsMobile(breakpoint = 768) {
|
|
|
5351
5677
|
}, [breakpoint]);
|
|
5352
5678
|
return isMobile;
|
|
5353
5679
|
}
|
|
5680
|
+
var DESKTOP_TOOLBAR_WRAP_WIDTH = 900;
|
|
5681
|
+
var WEB_TOOLBAR_WRAP_WIDTH = 700;
|
|
5354
5682
|
function FolderGlyph() {
|
|
5355
5683
|
return /* @__PURE__ */ jsx14(
|
|
5356
5684
|
"svg",
|
|
@@ -5382,12 +5710,35 @@ function FileGlyph() {
|
|
|
5382
5710
|
}
|
|
5383
5711
|
);
|
|
5384
5712
|
}
|
|
5713
|
+
function CollapseSidebarGlyph() {
|
|
5714
|
+
return /* @__PURE__ */ jsxs12(
|
|
5715
|
+
"svg",
|
|
5716
|
+
{
|
|
5717
|
+
viewBox: "0 0 64 64",
|
|
5718
|
+
fill: "none",
|
|
5719
|
+
stroke: "currentColor",
|
|
5720
|
+
strokeWidth: "3",
|
|
5721
|
+
strokeLinecap: "round",
|
|
5722
|
+
strokeLinejoin: "round",
|
|
5723
|
+
"aria-hidden": "true",
|
|
5724
|
+
children: [
|
|
5725
|
+
/* @__PURE__ */ jsx14("rect", { x: "7", y: "10", width: "50", height: "44", rx: "6" }),
|
|
5726
|
+
/* @__PURE__ */ jsx14("path", { d: "M24 10v44" }),
|
|
5727
|
+
/* @__PURE__ */ jsx14("path", { d: "m17 25-7 7 7 7" })
|
|
5728
|
+
]
|
|
5729
|
+
}
|
|
5730
|
+
);
|
|
5731
|
+
}
|
|
5385
5732
|
function DocBlocksShell({
|
|
5386
5733
|
theme: hostTheme = "auto",
|
|
5387
5734
|
logoUrl,
|
|
5388
5735
|
issueReportVersion,
|
|
5389
5736
|
appBuildDate,
|
|
5390
5737
|
ffmpegWasm,
|
|
5738
|
+
calcEngineFactory,
|
|
5739
|
+
proofing,
|
|
5740
|
+
proofingDefaultEnabled,
|
|
5741
|
+
proofingIgnoreStore,
|
|
5391
5742
|
homeDocumentTitle,
|
|
5392
5743
|
homeDocumentPath,
|
|
5393
5744
|
allowVersioning = true,
|
|
@@ -5440,6 +5791,11 @@ function DocBlocksShell({
|
|
|
5440
5791
|
setWriteCanvasSettings(settings);
|
|
5441
5792
|
saveWriteCanvasPreferences(settings);
|
|
5442
5793
|
}, []);
|
|
5794
|
+
const [proofingPreferences, setProofingPreferences] = useState15(loadProofingPreferences);
|
|
5795
|
+
const handleProofingPreferencesChange = useCallback15((settings) => {
|
|
5796
|
+
setProofingPreferences(settings);
|
|
5797
|
+
saveProofingPreferences(settings);
|
|
5798
|
+
}, []);
|
|
5443
5799
|
const [viewPreferences, setViewPreferences] = useState15(loadViewPreferences);
|
|
5444
5800
|
const handleViewPreferencesChange = useCallback15((prefs) => {
|
|
5445
5801
|
setViewPreferences(prefs);
|
|
@@ -5456,6 +5812,27 @@ function DocBlocksShell({
|
|
|
5456
5812
|
const [sidebarWidth, setSidebarWidth] = useState15(loadSidebarWidth);
|
|
5457
5813
|
const [compactLayout, setCompactLayout] = useState15(false);
|
|
5458
5814
|
const effectiveCompact = isMobile || compactLayout;
|
|
5815
|
+
const editorAreaRef = useRef15(null);
|
|
5816
|
+
const [desktopToolbarWrapped, setDesktopToolbarWrapped] = useState15(false);
|
|
5817
|
+
useEffect15(() => {
|
|
5818
|
+
const editorArea = editorAreaRef.current;
|
|
5819
|
+
if (!editorArea || effectiveCompact) {
|
|
5820
|
+
setDesktopToolbarWrapped(false);
|
|
5821
|
+
return;
|
|
5822
|
+
}
|
|
5823
|
+
const wrapWidth = isElectronHost3() ? DESKTOP_TOOLBAR_WRAP_WIDTH : WEB_TOOLBAR_WRAP_WIDTH;
|
|
5824
|
+
const updateWrappedState = () => {
|
|
5825
|
+
setDesktopToolbarWrapped(editorArea.getBoundingClientRect().width <= wrapWidth);
|
|
5826
|
+
};
|
|
5827
|
+
updateWrappedState();
|
|
5828
|
+
if (typeof ResizeObserver === "undefined") {
|
|
5829
|
+
window.addEventListener("resize", updateWrappedState);
|
|
5830
|
+
return () => window.removeEventListener("resize", updateWrappedState);
|
|
5831
|
+
}
|
|
5832
|
+
const observer = new ResizeObserver(updateWrappedState);
|
|
5833
|
+
observer.observe(editorArea);
|
|
5834
|
+
return () => observer.disconnect();
|
|
5835
|
+
}, [effectiveCompact]);
|
|
5459
5836
|
const showBrowserStorageWarning = !isElectronHost3();
|
|
5460
5837
|
const appVersion = isElectronHost3() ? `${getDocBlocksHost().env.appVersion} desktop` : issueReportVersion ?? "web";
|
|
5461
5838
|
const issueReportUrl = buildIssueReportUrl({
|
|
@@ -5501,13 +5878,13 @@ function DocBlocksShell({
|
|
|
5501
5878
|
lastRaw = drag.startWidth + (ev.clientX - drag.startX);
|
|
5502
5879
|
if (lastRaw < SIDEBAR_COLLAPSE_THRESHOLD && sidebarRef.current) {
|
|
5503
5880
|
sidebarRef.current.style.width = `${SIDEBAR_WIDTH_MIN}px`;
|
|
5504
|
-
sidebarRef.current.
|
|
5881
|
+
sidebarRef.current.classList.add("db-shell-sidebar--collapse-preview");
|
|
5505
5882
|
return;
|
|
5506
5883
|
}
|
|
5507
5884
|
const clamped = Math.min(SIDEBAR_WIDTH_MAX, Math.max(SIDEBAR_WIDTH_MIN, lastRaw));
|
|
5508
5885
|
if (sidebarRef.current) {
|
|
5509
5886
|
sidebarRef.current.style.width = `${clamped}px`;
|
|
5510
|
-
sidebarRef.current.
|
|
5887
|
+
sidebarRef.current.classList.remove("db-shell-sidebar--collapse-preview");
|
|
5511
5888
|
}
|
|
5512
5889
|
};
|
|
5513
5890
|
const onUp = () => {
|
|
@@ -5516,7 +5893,7 @@ function DocBlocksShell({
|
|
|
5516
5893
|
document.body.style.userSelect = "";
|
|
5517
5894
|
document.body.classList.remove("db-resizing-sidebar");
|
|
5518
5895
|
if (sidebarRef.current) {
|
|
5519
|
-
sidebarRef.current.
|
|
5896
|
+
sidebarRef.current.classList.remove("db-shell-sidebar--collapse-preview");
|
|
5520
5897
|
}
|
|
5521
5898
|
if (lastRaw < SIDEBAR_COLLAPSE_THRESHOLD) {
|
|
5522
5899
|
setCompactLayout(true);
|
|
@@ -5543,6 +5920,11 @@ function DocBlocksShell({
|
|
|
5543
5920
|
const [workspaceStartupError, setWorkspaceStartupError] = useState15(null);
|
|
5544
5921
|
const [activeWorkspaceId, setActiveWorkspaceId] = useState15(null);
|
|
5545
5922
|
const [activeWorkspaceDescriptor, setActiveWorkspaceDescriptor] = useState15(null);
|
|
5923
|
+
const defaultProofingIgnoreStore = useMemo3(
|
|
5924
|
+
() => createLocalProofingIgnoreStore(() => activeWorkspaceId),
|
|
5925
|
+
[activeWorkspaceId]
|
|
5926
|
+
);
|
|
5927
|
+
const effectiveProofingIgnoreStore = proofingIgnoreStore === void 0 ? defaultProofingIgnoreStore : proofingIgnoreStore;
|
|
5546
5928
|
useEffect15(() => {
|
|
5547
5929
|
if (!provider || getTransientWorkspace(provider.id)) return;
|
|
5548
5930
|
const providerV2 = getFileSystemProviderV27(provider);
|
|
@@ -5670,8 +6052,8 @@ function DocBlocksShell({
|
|
|
5670
6052
|
cancelled = true;
|
|
5671
6053
|
};
|
|
5672
6054
|
}, [activeWorkspaceDescriptor]);
|
|
5673
|
-
const
|
|
5674
|
-
const git = useGit(provider,
|
|
6055
|
+
const nativeWorkspaceId = provider && activeWorkspaceDescriptor?.id === activeWorkspaceId && provider.id === activeWorkspaceId && activeWorkspaceDescriptor.type === "electron-native" ? activeWorkspaceDescriptor.id : null;
|
|
6056
|
+
const git = useGit(provider, nativeWorkspaceId, resolvedTheme);
|
|
5675
6057
|
const gitRef = useRef15(git);
|
|
5676
6058
|
gitRef.current = git;
|
|
5677
6059
|
const { scheduleRefresh: gitScheduleRefresh } = git;
|
|
@@ -5699,11 +6081,13 @@ function DocBlocksShell({
|
|
|
5699
6081
|
const [selectedSourceFile, setSelectedSourceFile] = useState15(null);
|
|
5700
6082
|
const [selectedOutsideIn, setSelectedOutsideIn] = useState15(null);
|
|
5701
6083
|
const [selectedOutsideInEditingEnabled, setSelectedOutsideInEditingEnabled] = useState15(false);
|
|
6084
|
+
const [selectedImage, setSelectedImage] = useState15(void 0);
|
|
5702
6085
|
const adoptSelectedDocument = useCallback15((document2) => {
|
|
5703
6086
|
setSelectedFile(document2?.displayPath ?? null);
|
|
5704
6087
|
setSelectedSourceFile(document2?.sourcePath ?? null);
|
|
5705
6088
|
setSelectedOutsideIn(document2?.outsideIn ?? null);
|
|
5706
6089
|
setSelectedOutsideInEditingEnabled(document2?.outsideInEditingEnabled ?? false);
|
|
6090
|
+
setSelectedImage(document2?.image);
|
|
5707
6091
|
}, []);
|
|
5708
6092
|
const adoptRegularDocument = useCallback15((path) => {
|
|
5709
6093
|
if (path === null) {
|
|
@@ -5711,13 +6095,27 @@ function DocBlocksShell({
|
|
|
5711
6095
|
setSelectedSourceFile(null);
|
|
5712
6096
|
setSelectedOutsideIn(null);
|
|
5713
6097
|
setSelectedOutsideInEditingEnabled(false);
|
|
6098
|
+
setSelectedImage(void 0);
|
|
5714
6099
|
return;
|
|
5715
6100
|
}
|
|
5716
6101
|
setSelectedFile(path);
|
|
5717
6102
|
setSelectedSourceFile(path);
|
|
5718
6103
|
setSelectedOutsideIn(null);
|
|
5719
6104
|
setSelectedOutsideInEditingEnabled(false);
|
|
6105
|
+
setSelectedImage(void 0);
|
|
5720
6106
|
}, []);
|
|
6107
|
+
const selectedImageUrl = useMemo3(() => {
|
|
6108
|
+
if (!selectedImage || typeof URL === "undefined" || typeof URL.createObjectURL !== "function") {
|
|
6109
|
+
return void 0;
|
|
6110
|
+
}
|
|
6111
|
+
return URL.createObjectURL(new Blob([selectedImage.data], { type: selectedImage.mimeType }));
|
|
6112
|
+
}, [selectedImage]);
|
|
6113
|
+
useEffect15(
|
|
6114
|
+
() => () => {
|
|
6115
|
+
if (selectedImageUrl) URL.revokeObjectURL(selectedImageUrl);
|
|
6116
|
+
},
|
|
6117
|
+
[selectedImageUrl]
|
|
6118
|
+
);
|
|
5721
6119
|
useDocumentTitle(selectedFile, homeDocumentTitle, homeDocumentPath);
|
|
5722
6120
|
const exportDestinationAdapter = useMemo3(() => {
|
|
5723
6121
|
if (!selectedFile) return void 0;
|
|
@@ -6580,7 +6978,7 @@ function DocBlocksShell({
|
|
|
6580
6978
|
const providerV2 = getFileSystemProviderV27(provider);
|
|
6581
6979
|
if (!providerV2?.capabilities.watch) return;
|
|
6582
6980
|
const watchedFile = selectedSourceFile ?? selectedFile;
|
|
6583
|
-
if (!watchedFile || !documentSnapshot.targetKey) return;
|
|
6981
|
+
if (!watchedFile || !documentSnapshot.targetKey || selectedImage) return;
|
|
6584
6982
|
const targetKey = documentSnapshot.targetKey;
|
|
6585
6983
|
let disposed = false;
|
|
6586
6984
|
let reading = false;
|
|
@@ -6634,7 +7032,14 @@ function DocBlocksShell({
|
|
|
6634
7032
|
disposed = true;
|
|
6635
7033
|
void subscription.dispose();
|
|
6636
7034
|
};
|
|
6637
|
-
}, [
|
|
7035
|
+
}, [
|
|
7036
|
+
provider,
|
|
7037
|
+
selectedFile,
|
|
7038
|
+
selectedSourceFile,
|
|
7039
|
+
selectedImage,
|
|
7040
|
+
documentSession,
|
|
7041
|
+
documentSnapshot.targetKey
|
|
7042
|
+
]);
|
|
6638
7043
|
const transitionAwayFromDocument = useCallback15(
|
|
6639
7044
|
async (requestId) => {
|
|
6640
7045
|
if (requestId !== navigationRequestRef.current) return false;
|
|
@@ -7285,6 +7690,15 @@ function DocBlocksShell({
|
|
|
7285
7690
|
await getDocBlocksHost().shell.revealInFolder(ws.id);
|
|
7286
7691
|
}
|
|
7287
7692
|
}, [activeWorkspaceId]);
|
|
7693
|
+
const handleOpenWorkspaceFolder = useCallback15(() => {
|
|
7694
|
+
if (!isElectronHost3() || !nativeWorkspaceId) return;
|
|
7695
|
+
void getDocBlocksHost().shell.openWorkspaceFolder(nativeWorkspaceId).catch((error) => {
|
|
7696
|
+
showToast(
|
|
7697
|
+
"error",
|
|
7698
|
+
error instanceof Error ? error.message : "Could not open this workspace folder."
|
|
7699
|
+
);
|
|
7700
|
+
});
|
|
7701
|
+
}, [nativeWorkspaceId, showToast]);
|
|
7288
7702
|
useEffect15(() => {
|
|
7289
7703
|
if (!isElectronHost3()) return;
|
|
7290
7704
|
const host = getDocBlocksHost();
|
|
@@ -7481,6 +7895,13 @@ function DocBlocksShell({
|
|
|
7481
7895
|
},
|
|
7482
7896
|
[handleEnableOutsideInEditing, selectedFile, selectedOutsideInEditingEnabled]
|
|
7483
7897
|
);
|
|
7898
|
+
const actionsForEntry = useCallback15(
|
|
7899
|
+
(entry) => {
|
|
7900
|
+
const nativeActions = isElectronHost3() ? createNativeFileActions(entry, nativeWorkspaceId, getDocBlocksHost()) : [];
|
|
7901
|
+
return [...nativeActions, ...outsideInActionsForEntry(entry)];
|
|
7902
|
+
},
|
|
7903
|
+
[nativeWorkspaceId, outsideInActionsForEntry]
|
|
7904
|
+
);
|
|
7484
7905
|
const handleEditorLinkClick = useCallback15(
|
|
7485
7906
|
(href) => {
|
|
7486
7907
|
const target = resolveShellEditorLinkTarget(href, selectedSourceFile ?? selectedFile);
|
|
@@ -7630,7 +8051,7 @@ function DocBlocksShell({
|
|
|
7630
8051
|
const nextFile = selectedFile ? relocateProviderPath(selectedFile, change.oldPath, change.newPath) : null;
|
|
7631
8052
|
const nextFolder = selectedFolder ? relocateProviderPath(selectedFolder, change.oldPath, change.newPath) : null;
|
|
7632
8053
|
if (nextFile !== selectedFile) {
|
|
7633
|
-
if (nextFile
|
|
8054
|
+
if (nextFile) {
|
|
7634
8055
|
const opened = await loadEditableShellDocument(provider, nextFile);
|
|
7635
8056
|
adoptSelectedDocument(opened);
|
|
7636
8057
|
} else {
|
|
@@ -7675,7 +8096,6 @@ function DocBlocksShell({
|
|
|
7675
8096
|
adoptRegularDocument,
|
|
7676
8097
|
adoptSelectedDocument,
|
|
7677
8098
|
selectedFile,
|
|
7678
|
-
selectedOutsideIn,
|
|
7679
8099
|
selectedFolder,
|
|
7680
8100
|
activeWorkspaceId,
|
|
7681
8101
|
pinnedDocuments,
|
|
@@ -8304,7 +8724,7 @@ function DocBlocksShell({
|
|
|
8304
8724
|
return /* @__PURE__ */ jsx14(
|
|
8305
8725
|
"div",
|
|
8306
8726
|
{
|
|
8307
|
-
className: `db-shell${effectiveCompact ? " db-shell--mobile" : ""}`,
|
|
8727
|
+
className: `db-shell${effectiveCompact ? " db-shell--mobile" : ""}${desktopToolbarWrapped ? " db-shell--desktop-toolbar-wrapped" : ""}`,
|
|
8308
8728
|
"data-theme": resolvedTheme,
|
|
8309
8729
|
"data-accent": accentColor,
|
|
8310
8730
|
"data-document-status": documentSnapshot.status,
|
|
@@ -8365,6 +8785,8 @@ function DocBlocksShell({
|
|
|
8365
8785
|
onAccentColorChange: handleAccentColorChange,
|
|
8366
8786
|
writeCanvasSettings,
|
|
8367
8787
|
onWriteCanvasSettingsChange: handleWriteCanvasSettingsChange,
|
|
8788
|
+
proofingPreferences,
|
|
8789
|
+
onProofingPreferencesChange: handleProofingPreferencesChange,
|
|
8368
8790
|
versioningPreference,
|
|
8369
8791
|
onVersioningPreferenceChange: handleVersioningPreferenceChange,
|
|
8370
8792
|
onDownloadAllWorkspaces: handleDownloadAllWorkspaces,
|
|
@@ -8431,7 +8853,8 @@ function DocBlocksShell({
|
|
|
8431
8853
|
onPinnedDocumentDelete: handlePinnedDocumentDelete,
|
|
8432
8854
|
onTogglePin: handleTogglePin,
|
|
8433
8855
|
onSelect: handleSelect,
|
|
8434
|
-
|
|
8856
|
+
onOpenWorkspaceFolder: isElectronHost3() && nativeWorkspaceId ? handleOpenWorkspaceFolder : void 0,
|
|
8857
|
+
actionsForEntry,
|
|
8435
8858
|
onTreeMutation: handleTreeMutation,
|
|
8436
8859
|
onTreeChange: handleTreeChange,
|
|
8437
8860
|
onImportFiles: handleImportFiles,
|
|
@@ -8475,6 +8898,7 @@ function DocBlocksShell({
|
|
|
8475
8898
|
]
|
|
8476
8899
|
}
|
|
8477
8900
|
),
|
|
8901
|
+
git.available && git.pendingGrant && /* @__PURE__ */ jsx14(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx14(GitGrantNotice, {}) }),
|
|
8478
8902
|
/* @__PURE__ */ jsxs12("div", { className: "db-shell-sidebar-footer", children: [
|
|
8479
8903
|
/* @__PURE__ */ jsx14("a", { href: "https://docblocks.com/docs/", target: "_blank", rel: "noopener noreferrer", children: "Docs" }),
|
|
8480
8904
|
/* @__PURE__ */ jsx14("span", { className: "db-shell-sidebar-footer-separator", "aria-hidden": "true", children: "\u2022" }),
|
|
@@ -8494,6 +8918,10 @@ function DocBlocksShell({
|
|
|
8494
8918
|
}
|
|
8495
8919
|
)
|
|
8496
8920
|
] })
|
|
8921
|
+
] }),
|
|
8922
|
+
/* @__PURE__ */ jsxs12("div", { className: "db-sidebar-collapse-preview", "aria-hidden": "true", children: [
|
|
8923
|
+
/* @__PURE__ */ jsx14("span", { className: "db-sidebar-collapse-preview-icon", children: /* @__PURE__ */ jsx14(CollapseSidebarGlyph, {}) }),
|
|
8924
|
+
/* @__PURE__ */ jsx14("span", { className: "db-sidebar-collapse-preview-label", children: "Release to hide files" })
|
|
8497
8925
|
] })
|
|
8498
8926
|
]
|
|
8499
8927
|
}
|
|
@@ -8511,6 +8939,7 @@ function DocBlocksShell({
|
|
|
8511
8939
|
(!effectiveCompact || mobileShowEditor) && /* @__PURE__ */ jsxs12(
|
|
8512
8940
|
"main",
|
|
8513
8941
|
{
|
|
8942
|
+
ref: editorAreaRef,
|
|
8514
8943
|
"aria-label": "Document editor",
|
|
8515
8944
|
className: updateAvailable && onApplyUpdate && updateStatusBarVisible ? "db-shell-editor-area db-shell-editor-area--has-update" : "db-shell-editor-area",
|
|
8516
8945
|
style: {
|
|
@@ -8530,11 +8959,13 @@ function DocBlocksShell({
|
|
|
8530
8959
|
EditorShell,
|
|
8531
8960
|
{
|
|
8532
8961
|
initialMarkdown: editorContent,
|
|
8533
|
-
readOnly: selectedOutsideIn !== null && !selectedOutsideInEditingEnabled,
|
|
8962
|
+
readOnly: selectedImage !== void 0 || selectedOutsideIn !== null && !selectedOutsideInEditingEnabled,
|
|
8534
8963
|
initialView,
|
|
8535
8964
|
defaultViewportPreset: defaultPreviewViewportPreset,
|
|
8536
8965
|
articleId: selectedFile,
|
|
8537
8966
|
fileName: selectedFile,
|
|
8967
|
+
imageSrc: selectedImageUrl,
|
|
8968
|
+
imageAlt: basenameOf(selectedFile),
|
|
8538
8969
|
saveCoverImageOutput: saveRenderedImageOutput,
|
|
8539
8970
|
saveDashboardImageOutput: saveRenderedImageOutput,
|
|
8540
8971
|
onChange: handleEditorChange,
|
|
@@ -8545,6 +8976,12 @@ function DocBlocksShell({
|
|
|
8545
8976
|
placeholder: editorPlaceholder,
|
|
8546
8977
|
outlineWidth: 280,
|
|
8547
8978
|
mediaProvider,
|
|
8979
|
+
calcEngineFactory,
|
|
8980
|
+
proofing,
|
|
8981
|
+
proofingDefaultEnabled,
|
|
8982
|
+
proofingSpellingEnabled: proofingPreferences.spelling,
|
|
8983
|
+
proofingGrammarEnabled: proofingPreferences.grammar,
|
|
8984
|
+
proofingIgnoreStore: effectiveProofingIgnoreStore,
|
|
8548
8985
|
showCodeCopyButton,
|
|
8549
8986
|
onCopyCode,
|
|
8550
8987
|
allowRecording,
|
|
@@ -8552,7 +8989,7 @@ function DocBlocksShell({
|
|
|
8552
8989
|
allowPresentationFullscreen,
|
|
8553
8990
|
documentLinkProvider,
|
|
8554
8991
|
workspaceContainer: versionsContainer ?? void 0,
|
|
8555
|
-
allowVersioning: effectiveVersioning,
|
|
8992
|
+
allowVersioning: selectedImage === void 0 && effectiveVersioning,
|
|
8556
8993
|
viewPreferences,
|
|
8557
8994
|
onViewPreferencesChange: handleViewPreferencesChange,
|
|
8558
8995
|
versionBasename: versionBasename ?? stripExtension(basenameOf(selectedFile)),
|
|
@@ -8695,12 +9132,14 @@ export {
|
|
|
8695
9132
|
AccentColorSettings,
|
|
8696
9133
|
AppMenu,
|
|
8697
9134
|
DEFAULT_OPTIONS,
|
|
9135
|
+
DEFAULT_PROOFING_PREFERENCES,
|
|
8698
9136
|
DEFAULT_WRITE_CANVAS_FONT_SCHEME,
|
|
8699
9137
|
DocBlocksShell,
|
|
8700
9138
|
ExportDialog,
|
|
8701
9139
|
ExportToolbarControls,
|
|
8702
9140
|
FileExplorer,
|
|
8703
9141
|
FileTreeNode,
|
|
9142
|
+
ProofingSettingsControls,
|
|
8704
9143
|
SettingsDialog,
|
|
8705
9144
|
ThemeSettings,
|
|
8706
9145
|
WRITE_CANVAS_FONT_SCHEMES,
|
|
@@ -8711,8 +9150,10 @@ export {
|
|
|
8711
9150
|
createImageSaveOutput as createDashboardImageSaveOutput,
|
|
8712
9151
|
createImageSaveOutput,
|
|
8713
9152
|
loadLastExportOptions,
|
|
9153
|
+
loadProofingPreferences,
|
|
8714
9154
|
resolveWriteCanvasFonts,
|
|
8715
9155
|
runExport,
|
|
9156
|
+
saveProofingPreferences,
|
|
8716
9157
|
updateExportTargetExtension,
|
|
8717
9158
|
useDocumentSession,
|
|
8718
9159
|
useFileTree
|