@jxsuite/studio 2.4.3 → 4.0.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 +5 -5
- package/dist/chunks/Overlay.dev-723bv0df.js +23 -0
- package/dist/chunks/cf-settings-45fgyx8y.js +21 -0
- package/dist/chunks/{components-z6cnkyy1.js → components-zmx10t62.js} +6 -5
- package/dist/chunks/content-source-t88vb2dr.js +49 -0
- package/dist/chunks/{convert-to-repeater-k10dvcc7.js → convert-to-repeater-dhw1nrz9.js} +27 -18
- package/dist/chunks/entry-commands-6z6bhxg0.js +46 -0
- package/dist/chunks/{extension-sections-0ada0xcw.js → extension-sections-3ydgjbdy.js} +32 -23
- package/dist/chunks/file-ops-rskmhxyq.js +48 -0
- package/dist/chunks/files-0cratsr0.js +92 -0
- package/dist/chunks/{format-host-wewba4nq.js → format-host-tgcmfs4p.js} +3 -3
- package/dist/chunks/fs-events-hrrg328g.js +21 -0
- package/dist/chunks/{git-panel-2dh1aw50.js → git-panel-0yywyk76.js} +21 -15
- package/dist/chunks/{jx-validate-jj9rnt4n.js → jx-validate-8q2g05x1.js} +6 -4
- package/dist/chunks/layers-panel-z3tqe5cd.js +67 -0
- package/dist/chunks/layers-q75tj2mf.js +45 -0
- package/dist/chunks/lit-html-j055mkh8.js +22 -0
- package/dist/chunks/monaco-buffer-dqw0xxpx.js +25 -0
- package/dist/chunks/{monaco-setup-a5wkmbgh.js → monaco-setup-rws7k4br.js} +4 -4
- package/dist/chunks/notify-yjm79n4s.js +30 -0
- package/dist/chunks/parse-24d0gay3.js +19 -0
- package/dist/chunks/platform-ba1j1gbh.js +16 -0
- package/dist/chunks/publish-panel-54jvhskq.js +28 -0
- package/dist/chunks/quick-search-cgfmjwq5.js +65 -0
- package/dist/chunks/references-3qx8fkyp.js +29 -0
- package/dist/chunks/right-panel-cqp8bc4v.js +46 -0
- package/dist/chunks/sp-overlay.dev-yztmtrs1.js +18 -0
- package/dist/chunks/sp-popover.dev-n2etmqdp.js +9 -0
- package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +15 -0
- package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +15 -0
- package/dist/chunks/{sp-tray.dev-64v4pxw8.js → sp-tray.dev-tkbscm06.js} +5 -5
- package/dist/chunks/{studio-f5yyvqxv.js → studio-1hbqnt19.js} +37 -31
- package/dist/chunks/studio-2zkz8evn.js +3163 -0
- package/dist/chunks/{studio-0b6fs05q.js → studio-4pqqxbrt.js} +23 -15
- package/dist/chunks/{studio-kvfx9z2c.js → studio-4rzyrtjz.js} +70 -31
- package/dist/chunks/{studio-ef8t53vc.js → studio-5q69gfag.js} +60 -56
- package/dist/chunks/{studio-v2c5pmjj.js → studio-5rywrkxz.js} +565 -133
- package/dist/chunks/{studio-6kv3apa9.js → studio-68n67094.js} +25 -9
- package/dist/chunks/{studio-0rqqhrdy.js → studio-7nte2hj4.js} +2 -2
- package/dist/chunks/{studio-hyn3vhwr.js → studio-8swrjbny.js} +31 -18
- package/dist/chunks/studio-92ab2jqe.js +282 -0
- package/dist/chunks/{studio-sas7mt3k.js → studio-9ab8gqsm.js} +2 -2
- package/dist/chunks/{studio-28xc8ws4.js → studio-9c4k4vhv.js} +14 -10
- package/dist/chunks/studio-9n4mrmnb.js +184 -0
- package/dist/chunks/{studio-tr20m8g8.js → studio-9r6j5ev1.js} +37 -2
- package/dist/chunks/{studio-aweyr4v1.js → studio-ahjfdy6e.js} +9 -7
- package/dist/chunks/{studio-s519zc99.js → studio-bgxt93ga.js} +3 -3
- package/dist/chunks/{studio-26sv44br.js → studio-cb12yz9w.js} +8543 -8784
- package/dist/chunks/studio-cft9r4r7.js +119 -0
- package/dist/chunks/{studio-rqemfhz6.js → studio-eenfkt4e.js} +6 -6
- package/dist/chunks/studio-eesa1myv.js +498 -0
- package/dist/chunks/{studio-ay8wcr2b.js → studio-eqq1w638.js} +7 -9
- package/dist/chunks/{studio-ke244pam.js → studio-ex8zyp98.js} +51 -25
- package/dist/chunks/studio-gv8vvshc.js +118 -0
- package/dist/chunks/studio-hbtp0eh1.js +1315 -0
- package/dist/chunks/{studio-cz2j1c0g.js → studio-htsf0w6m.js} +75 -123
- package/dist/chunks/{studio-pyrw8h0w.js → studio-kjjsjak4.js} +528 -212
- package/dist/chunks/{studio-5x5774ak.js → studio-kryvsw6j.js} +3 -3
- package/dist/chunks/studio-kyh9avvv.js +28 -0
- package/dist/chunks/{studio-jnakhg87.js → studio-kyk2v92a.js} +14 -14
- package/dist/chunks/{studio-twsafr1e.js → studio-m3hwn7y1.js} +3 -3
- package/dist/chunks/{studio-tzx3xmvx.js → studio-mmv72a27.js} +8 -8
- package/dist/chunks/{studio-vhk5fmfv.js → studio-n8b9wqwy.js} +5 -5
- package/dist/chunks/{studio-cjm7fdjf.js → studio-p4ngc046.js} +8 -104
- package/dist/chunks/{studio-sccge2wf.js → studio-p8j86wag.js} +2 -2
- package/dist/chunks/{studio-v1va0vhd.js → studio-pdfjntbk.js} +75 -139
- package/dist/chunks/studio-q43a5y9h.js +394 -0
- package/dist/chunks/studio-q7v10cg2.js +106 -0
- package/dist/chunks/{studio-2w11grav.js → studio-qq6jym04.js} +3 -3
- package/dist/chunks/studio-r1r7afxx.js +1066 -0
- package/dist/chunks/{studio-3fk1ac9z.js → studio-rdx8jcxy.js} +4 -4
- package/dist/chunks/{studio-4mqb9a0j.js → studio-rn9ta2mz.js} +4 -4
- package/dist/chunks/studio-sf7zjgv1.js +91 -0
- package/dist/chunks/studio-t7qb9db8.js +665 -0
- package/dist/chunks/studio-tmc5emrw.js +8 -0
- package/dist/chunks/{studio-wdt9y92a.js → studio-txwkm6p9.js} +2 -2
- package/dist/chunks/{studio-dgj7gq44.js → studio-v38hmvx1.js} +7 -7
- package/dist/chunks/{studio-7ejemhej.js → studio-vadzgkrz.js} +6 -6
- package/dist/chunks/studio-wcy8trfx.js +263 -0
- package/dist/chunks/{studio-hb7c46jy.js → studio-wx5609xd.js} +21 -15
- package/dist/chunks/studio-xrapxwwc.js +1539 -0
- package/dist/chunks/{studio-ws6ef6js.js → studio-yxrkyv8a.js} +41 -29
- package/dist/chunks/{studio-xm3dbxvn.js → studio-zczps70q.js} +2 -2
- package/dist/chunks/workspace-xpres40v.js +89 -0
- package/dist/iframe-entry.js +450 -48
- package/dist/studio.js +2455 -1761
- package/package.json +16 -15
- package/src/browse/library-layouts.ts +3 -3
- package/src/browse/library-pane.ts +59 -5
- package/src/browse/library-preview.ts +19 -3
- package/src/canvas/asset-refs.ts +119 -0
- package/src/canvas/asset-resolve.ts +256 -0
- package/src/canvas/canvas-live-render.ts +23 -15
- package/src/canvas/canvas-render.ts +23 -1
- package/src/canvas/iframe-entry.ts +1 -0
- package/src/canvas/iframe-host.ts +4 -0
- package/src/canvas/iframe-patch.ts +47 -21
- package/src/canvas/iframe-protocol.ts +9 -0
- package/src/canvas/iframe-render.ts +50 -16
- package/src/commands/app-commands.ts +4 -0
- package/src/commands/command-args.ts +29 -0
- package/src/commands/context.ts +15 -1
- package/src/commands/defaults.ts +29 -1
- package/src/commands/levels.ts +16 -0
- package/src/commands/live-context.ts +3 -0
- package/src/content/collection-match.ts +267 -0
- package/src/content/entry-commands.ts +38 -29
- package/src/content/entry-fields.ts +6 -0
- package/src/editor/file-drop-action.ts +2 -1
- package/src/editor/shortcuts.ts +5 -0
- package/src/files/file-ops.ts +10 -42
- package/src/files/files.ts +487 -61
- package/src/files/fs-events.ts +9 -0
- package/src/files/gitignore.ts +432 -0
- package/src/files/media-paths.ts +37 -14
- package/src/files/media-upload.ts +47 -6
- package/src/files/serialize-document.ts +60 -0
- package/src/format/convert-file.ts +511 -0
- package/src/format/format-choices.ts +199 -0
- package/src/grid/grid-idle.ts +45 -0
- package/src/grid/grid-view.ts +35 -0
- package/src/grid/schema-columns.ts +2 -1
- package/src/grid/sources/content-source.ts +24 -3
- package/src/media/media-open.ts +58 -0
- package/src/media/media-pane.ts +310 -0
- package/src/new-project/import-tab.ts +333 -160
- package/src/new-project/new-project-modal.ts +27 -34
- package/src/packages/ensure-deps.ts +14 -7
- package/src/packages/jxsuite-update.ts +11 -11
- package/src/page-params.ts +10 -46
- package/src/panels/activity-bar.ts +45 -16
- package/src/panels/ai-chat/attached-context.ts +6 -1
- package/src/panels/ai-chat/chat-view.ts +255 -13
- package/src/panels/ai-chat/composer.ts +21 -80
- package/src/panels/ai-panel.ts +116 -2
- package/src/panels/frontmatter-fields.ts +6 -2
- package/src/panels/navigator-panels.ts +7 -6
- package/src/panels/properties-panel.ts +8 -2
- package/src/panels/seo-modal.ts +5 -6
- package/src/panels/settings-menu.ts +799 -0
- package/src/panels/signals-panel.ts +2 -1
- package/src/panels/toolbar.ts +135 -15
- package/src/platforms/cloud.ts +34 -3
- package/src/platforms/devserver.ts +72 -34
- package/src/preview/preview-overlay.ts +226 -0
- package/src/services/ai-ask.ts +247 -0
- package/src/services/ai-import-tools.ts +494 -0
- package/src/services/ai-models.ts +101 -11
- package/src/services/ai-project-tools.ts +20 -26
- package/src/services/ai-settings.ts +69 -71
- package/src/services/ai-system-prompt.ts +88 -2
- package/src/services/ai-turn-signal.ts +70 -0
- package/src/services/cf-settings.ts +19 -37
- package/src/services/connection.ts +74 -0
- package/src/services/context-manager.ts +89 -0
- package/src/services/document-assistant.ts +49 -7
- package/src/services/idle.ts +6 -1
- package/src/services/import-client.ts +33 -6
- package/src/services/import-run.ts +158 -0
- package/src/services/import-seed.ts +120 -0
- package/src/services/jx-validate.ts +58 -6
- package/src/services/project-adoption.ts +71 -0
- package/src/services/references.ts +0 -0
- package/src/services/settings/definitions.ts +181 -0
- package/src/services/settings/kernel.ts +335 -0
- package/src/services/settings/write-queue.ts +116 -0
- package/src/services/tool-executor.ts +34 -2
- package/src/settings/contexts-section.ts +45 -3
- package/src/settings/dependencies-editor.ts +43 -23
- package/src/settings/general-settings.ts +30 -12
- package/src/settings/preferences-accounts.ts +6 -19
- package/src/settings/preferences-dialog.ts +18 -41
- package/src/settings/preferences-keymap.ts +8 -18
- package/src/settings/preferences-sections.ts +57 -0
- package/src/settings/schema-field-ui.ts +2 -2
- package/src/settings/settings-document.ts +65 -9
- package/src/shell.ts +6 -14
- package/src/studio.ts +65 -7
- package/src/tabs/transact.ts +42 -19
- package/src/types.ts +164 -8
- package/src/ui/ai-credentials-form.ts +52 -27
- package/src/ui/ai-model-picker.ts +162 -0
- package/src/ui/choice-field.ts +72 -0
- package/src/ui/layers.ts +83 -5
- package/src/ui/media-picker.ts +6 -11
- package/src/utils/studio-utils.ts +43 -31
- package/styles/forced-colors.css +7 -0
- package/styles/overlays.css +256 -0
- package/styles/panels.css +13 -1
- package/styles/shell.css +111 -0
- package/dist/chunks/Overlay.dev-d2ajy6sj.js +0 -23
- package/dist/chunks/cf-settings-g5fbf2zp.js +0 -17
- package/dist/chunks/content-source-k9724vcv.js +0 -39
- package/dist/chunks/files-yew27sn9.js +0 -69
- package/dist/chunks/layers-panel-qnsghwwd.js +0 -59
- package/dist/chunks/publish-panel-a0pdft5w.js +0 -21
- package/dist/chunks/quick-search-9avyc4pc.js +0 -54
- package/dist/chunks/right-panel-kcnhtc5j.js +0 -38
- package/dist/chunks/sp-overlay.dev-s18hymn9.js +0 -18
- package/dist/chunks/sp-popover.dev-dj9x7e7a.js +0 -9
- package/dist/chunks/sp-progress-circle.dev-0zxcyz3r.js +0 -15
- package/dist/chunks/sp-tooltip.dev-5c6d1kjz.js +0 -15
- package/dist/chunks/studio-a7pzveq1.js +0 -110
- package/dist/chunks/studio-c31yb4t6.js +0 -55
- package/dist/chunks/studio-ra7ar50f.js +0 -6682
- package/src/canvas/content-assets.ts +0 -263
- package/src/canvas/site-style-css.ts +0 -121
- package/src/services/settings-store.ts +0 -99
|
@@ -3,76 +3,117 @@ import {
|
|
|
3
3
|
measuredRowHeight,
|
|
4
4
|
revealListRow,
|
|
5
5
|
watchListWindow
|
|
6
|
-
} from "./studio-
|
|
6
|
+
} from "./studio-p8j86wag.js";
|
|
7
|
+
import {
|
|
8
|
+
formatBytes,
|
|
9
|
+
loadMediaMeta,
|
|
10
|
+
peekMediaMeta,
|
|
11
|
+
recordImageSize
|
|
12
|
+
} from "./studio-gv8vvshc.js";
|
|
7
13
|
import {
|
|
8
14
|
autoSyncProjectOnOpen,
|
|
9
15
|
cleanupGitPanel,
|
|
10
16
|
maybePromptJxsuiteUpdate,
|
|
11
17
|
shouldInstallAutomation
|
|
12
|
-
} from "./studio-
|
|
18
|
+
} from "./studio-ex8zyp98.js";
|
|
19
|
+
import {
|
|
20
|
+
collectionOfPath
|
|
21
|
+
} from "./studio-sf7zjgv1.js";
|
|
13
22
|
import {
|
|
14
23
|
openCsvGridTab,
|
|
15
24
|
openPagesGrid
|
|
16
|
-
} from "./studio-
|
|
25
|
+
} from "./studio-4pqqxbrt.js";
|
|
17
26
|
import {
|
|
18
|
-
collectionDirs,
|
|
19
|
-
collectionInfo,
|
|
20
27
|
confirmFileDelete,
|
|
21
|
-
|
|
28
|
+
disarmPreviewOverlay,
|
|
29
|
+
loadMediaUsages,
|
|
30
|
+
mediaUsageHeadline,
|
|
22
31
|
parseSourceForPath,
|
|
32
|
+
peekMediaUsages,
|
|
23
33
|
renamePromptMessage
|
|
24
|
-
} from "./studio-
|
|
34
|
+
} from "./studio-cb12yz9w.js";
|
|
25
35
|
import {
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
ensureIgnoreLayers,
|
|
37
|
+
isIgnoredEntry,
|
|
38
|
+
markLocalMutation,
|
|
39
|
+
resetIgnoreCache
|
|
40
|
+
} from "./studio-q43a5y9h.js";
|
|
41
|
+
import {
|
|
42
|
+
extensionOf,
|
|
28
43
|
isImage,
|
|
44
|
+
isMediaFile,
|
|
45
|
+
mediaKind,
|
|
46
|
+
mediaSiteUrl,
|
|
47
|
+
previewFileSrc,
|
|
48
|
+
uploadAccept,
|
|
29
49
|
uploadAssets
|
|
30
|
-
} from "./studio-
|
|
50
|
+
} from "./studio-htsf0w6m.js";
|
|
51
|
+
import {
|
|
52
|
+
invalidateUsages
|
|
53
|
+
} from "./studio-cft9r4r7.js";
|
|
31
54
|
import {
|
|
32
55
|
showProgressModal
|
|
33
|
-
} from "./studio-
|
|
56
|
+
} from "./studio-9c4k4vhv.js";
|
|
34
57
|
import {
|
|
35
58
|
rectOf,
|
|
36
59
|
registerPanel
|
|
37
|
-
} from "./studio-
|
|
60
|
+
} from "./studio-kjjsjak4.js";
|
|
61
|
+
import {
|
|
62
|
+
markSessionRestored,
|
|
63
|
+
persistedSession,
|
|
64
|
+
resetProjectShell,
|
|
65
|
+
restoreSession,
|
|
66
|
+
setActivityTab
|
|
67
|
+
} from "./studio-hbtp0eh1.js";
|
|
38
68
|
import {
|
|
39
|
-
activateTab,
|
|
40
69
|
activeRegistry,
|
|
41
|
-
|
|
42
|
-
|
|
70
|
+
paneRegion,
|
|
71
|
+
renderPopover,
|
|
72
|
+
showPromptDialog
|
|
73
|
+
} from "./studio-t7qb9db8.js";
|
|
74
|
+
import {
|
|
75
|
+
errorMessage
|
|
76
|
+
} from "./studio-9n4mrmnb.js";
|
|
77
|
+
import {
|
|
78
|
+
activateTab,
|
|
79
|
+
collectionForDirectory,
|
|
80
|
+
collectionForFile,
|
|
43
81
|
isCollabPath,
|
|
44
82
|
localeLabel,
|
|
45
83
|
localeOfPath,
|
|
46
|
-
markSessionRestored,
|
|
47
84
|
moveTabToPane,
|
|
48
|
-
notify,
|
|
49
|
-
now,
|
|
50
85
|
openTab,
|
|
51
86
|
paneOfTab,
|
|
52
|
-
persistedSession,
|
|
53
87
|
receivingPane,
|
|
54
88
|
renameTab,
|
|
55
|
-
renderPopover,
|
|
56
89
|
replaceAllTabs,
|
|
57
|
-
resetProjectShell,
|
|
58
90
|
resolveI18n,
|
|
59
|
-
restoreSession,
|
|
60
|
-
setActivityTab,
|
|
61
91
|
setWorkspaceProject,
|
|
62
|
-
showPromptDialog,
|
|
63
92
|
workspace
|
|
64
|
-
} from "./studio-
|
|
93
|
+
} from "./studio-2zkz8evn.js";
|
|
94
|
+
import {
|
|
95
|
+
SETTINGS,
|
|
96
|
+
readStoredSetting,
|
|
97
|
+
setSetting
|
|
98
|
+
} from "./studio-92ab2jqe.js";
|
|
99
|
+
import {
|
|
100
|
+
effect,
|
|
101
|
+
effectScope,
|
|
102
|
+
notify,
|
|
103
|
+
now
|
|
104
|
+
} from "./studio-xrapxwwc.js";
|
|
65
105
|
import {
|
|
66
106
|
classMap
|
|
67
|
-
} from "./studio-
|
|
107
|
+
} from "./studio-m3hwn7y1.js";
|
|
68
108
|
import {
|
|
69
109
|
ref,
|
|
70
110
|
repeat
|
|
71
|
-
} from "./studio-
|
|
111
|
+
} from "./studio-4rzyrtjz.js";
|
|
72
112
|
import {
|
|
73
113
|
html,
|
|
74
|
-
nothing
|
|
75
|
-
|
|
114
|
+
nothing,
|
|
115
|
+
render
|
|
116
|
+
} from "./studio-kryvsw6j.js";
|
|
76
117
|
import {
|
|
77
118
|
combine,
|
|
78
119
|
draggable,
|
|
@@ -81,42 +122,47 @@ import {
|
|
|
81
122
|
} from "./studio-g1wdche0.js";
|
|
82
123
|
import {
|
|
83
124
|
loadComponentRegistry
|
|
84
|
-
} from "./studio-
|
|
125
|
+
} from "./studio-bgxt93ga.js";
|
|
85
126
|
import {
|
|
86
127
|
projectState,
|
|
87
128
|
requireProjectState,
|
|
88
129
|
setProjectState
|
|
89
|
-
} from "./studio-
|
|
130
|
+
} from "./studio-p4ngc046.js";
|
|
90
131
|
import {
|
|
91
132
|
documentExtensions,
|
|
133
|
+
formatByExtension,
|
|
92
134
|
formatForPath,
|
|
135
|
+
getFormats,
|
|
93
136
|
loadFormats,
|
|
94
137
|
noFormatError,
|
|
95
138
|
refreshExtensionUi,
|
|
96
139
|
refreshFormats
|
|
97
|
-
} from "./studio-
|
|
140
|
+
} from "./studio-eenfkt4e.js";
|
|
98
141
|
import {
|
|
99
142
|
getPlatform,
|
|
100
143
|
hasPlatform
|
|
101
|
-
} from "./studio-
|
|
144
|
+
} from "./studio-9ab8gqsm.js";
|
|
145
|
+
import {
|
|
146
|
+
__require
|
|
147
|
+
} from "./studio-a0tswy0w.js";
|
|
102
148
|
|
|
103
149
|
// src/packages/ensure-deps.ts
|
|
104
150
|
async function ensureDependenciesInstalled() {
|
|
105
151
|
if (shouldInstallAutomation(location.search)) {
|
|
106
|
-
return;
|
|
152
|
+
return false;
|
|
107
153
|
}
|
|
108
154
|
const platform = getPlatform();
|
|
109
155
|
if (!platform.dependenciesNeedInstall || !platform.installDependencies) {
|
|
110
|
-
return;
|
|
156
|
+
return false;
|
|
111
157
|
}
|
|
112
158
|
let needs = false;
|
|
113
159
|
try {
|
|
114
160
|
needs = await platform.dependenciesNeedInstall();
|
|
115
161
|
} catch {
|
|
116
|
-
return;
|
|
162
|
+
return false;
|
|
117
163
|
}
|
|
118
164
|
if (!needs) {
|
|
119
|
-
return;
|
|
165
|
+
return false;
|
|
120
166
|
}
|
|
121
167
|
const progress = showProgressModal({
|
|
122
168
|
status: "Running bun install…",
|
|
@@ -126,89 +172,287 @@ async function ensureDependenciesInstalled() {
|
|
|
126
172
|
const result = await platform.installDependencies();
|
|
127
173
|
if (result.ok) {
|
|
128
174
|
progress.done();
|
|
129
|
-
|
|
130
|
-
progress.fail(result.log ?? "bun install failed");
|
|
175
|
+
return true;
|
|
131
176
|
}
|
|
177
|
+
progress.fail(result.log ?? "bun install failed");
|
|
132
178
|
} catch (error) {
|
|
133
179
|
progress.fail(error instanceof Error ? error.message : String(error));
|
|
134
180
|
}
|
|
181
|
+
return false;
|
|
135
182
|
}
|
|
136
183
|
|
|
137
|
-
// src/
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
184
|
+
// src/media/media-pane.ts
|
|
185
|
+
var MEDIA_MODE = "media";
|
|
186
|
+
var FONT_EXTENSIONS = new Set([".woff", ".woff2", ".ttf", ".otf"]);
|
|
187
|
+
var SPECIMEN = "The quick brown fox jumps over the lazy dog";
|
|
188
|
+
var SPECIMEN_SIZES = [48, 32, 24, 18, 14];
|
|
189
|
+
var _active = new Map;
|
|
190
|
+
function activeIn(paneId) {
|
|
191
|
+
return _active.get(paneId) ?? null;
|
|
192
|
+
}
|
|
193
|
+
function mediaPaneMounted(paneId, tab) {
|
|
194
|
+
const panel = activeIn(paneId);
|
|
195
|
+
return panel !== null && panel.tabId === tab.id && panel.wrap.isConnected;
|
|
196
|
+
}
|
|
197
|
+
function detachMediaPane(paneId) {
|
|
198
|
+
const panel = _active.get(paneId);
|
|
199
|
+
if (!panel) {
|
|
200
|
+
return;
|
|
145
201
|
}
|
|
146
|
-
|
|
147
|
-
|
|
202
|
+
panel.scope.stop();
|
|
203
|
+
_active.delete(paneId);
|
|
204
|
+
}
|
|
205
|
+
function assetTpl(path, src, redraw) {
|
|
206
|
+
const ext = extensionOf(path);
|
|
207
|
+
const kind = mediaKind({ name: path });
|
|
208
|
+
if (FONT_EXTENSIONS.has(ext)) {
|
|
209
|
+
const family = `jx-specimen-${path.replaceAll(/[^a-zA-Z0-9]/g, "-")}`;
|
|
210
|
+
return html`
|
|
211
|
+
<style>
|
|
212
|
+
@font-face {
|
|
213
|
+
font-family: "${family}";
|
|
214
|
+
src: url("${src}");
|
|
215
|
+
}
|
|
216
|
+
</style>
|
|
217
|
+
<div class="media-specimen" style="font-family: '${family}', system-ui, sans-serif">
|
|
218
|
+
${SPECIMEN_SIZES.map((size) => html`<p class="media-specimen-line" style="font-size: ${size}px">
|
|
219
|
+
${SPECIMEN}
|
|
220
|
+
</p>`)}
|
|
221
|
+
</div>
|
|
222
|
+
`;
|
|
223
|
+
}
|
|
224
|
+
switch (kind) {
|
|
225
|
+
case "image": {
|
|
226
|
+
return html`<img
|
|
227
|
+
class="media-image"
|
|
228
|
+
src=${src}
|
|
229
|
+
alt=""
|
|
230
|
+
@load=${(e) => {
|
|
231
|
+
const img = e.target;
|
|
232
|
+
if (recordImageSize(path, img.naturalWidth, img.naturalHeight)) {
|
|
233
|
+
redraw();
|
|
234
|
+
}
|
|
235
|
+
}}
|
|
236
|
+
/>`;
|
|
237
|
+
}
|
|
238
|
+
case "video": {
|
|
239
|
+
return html`<video class="media-video" src=${src} controls></video>`;
|
|
240
|
+
}
|
|
241
|
+
case "audio": {
|
|
242
|
+
return html`<audio class="media-audio" src=${src} controls></audio>`;
|
|
243
|
+
}
|
|
244
|
+
default: {
|
|
245
|
+
return ext === ".pdf" ? html`<embed class="media-embed" src=${src} type="application/pdf" />` : html`<div class="media-unviewable">
|
|
246
|
+
<p>Jx has no viewer for <code>${ext || "this file"}</code>.</p>
|
|
247
|
+
<p class="media-note">The file is in the project and builds normally.</p>
|
|
248
|
+
</div>`;
|
|
249
|
+
}
|
|
148
250
|
}
|
|
149
|
-
return {
|
|
150
|
-
def: info.def,
|
|
151
|
-
dir: info.dir,
|
|
152
|
-
ext: info.ext,
|
|
153
|
-
name: info.name,
|
|
154
|
-
schema: info.def.schema ?? null
|
|
155
|
-
};
|
|
156
251
|
}
|
|
157
|
-
function
|
|
158
|
-
|
|
252
|
+
function factsTpl(path, meta) {
|
|
253
|
+
const facts = [mediaKind({ name: path })];
|
|
254
|
+
if (meta?.width != null && meta.height != null) {
|
|
255
|
+
facts.push(`${meta.width} × ${meta.height}`);
|
|
256
|
+
}
|
|
257
|
+
if (meta?.bytes != null) {
|
|
258
|
+
facts.push(formatBytes(meta.bytes));
|
|
259
|
+
}
|
|
260
|
+
if (meta?.modified) {
|
|
261
|
+
facts.push(`modified ${meta.modified.slice(0, 10)}`);
|
|
262
|
+
}
|
|
263
|
+
return html`<p class="media-facts">${facts.join(" · ")}</p>`;
|
|
159
264
|
}
|
|
160
|
-
function
|
|
161
|
-
const
|
|
162
|
-
return
|
|
265
|
+
function refTpl(path) {
|
|
266
|
+
const ref2 = mediaSiteUrl(path);
|
|
267
|
+
return html`
|
|
268
|
+
<div class="media-ref">
|
|
269
|
+
<code class="media-ref-value">${ref2}</code>
|
|
270
|
+
<sp-action-button
|
|
271
|
+
size="s"
|
|
272
|
+
quiet
|
|
273
|
+
title="Copy the reference"
|
|
274
|
+
@click=${() => {
|
|
275
|
+
navigator.clipboard?.writeText(ref2);
|
|
276
|
+
}}
|
|
277
|
+
>Copy</sp-action-button
|
|
278
|
+
>
|
|
279
|
+
</div>
|
|
280
|
+
`;
|
|
163
281
|
}
|
|
164
|
-
function
|
|
165
|
-
|
|
166
|
-
|
|
282
|
+
function usageTpl(usage) {
|
|
283
|
+
const headline = mediaUsageHeadline(usage);
|
|
284
|
+
if (headline === null) {
|
|
285
|
+
return nothing;
|
|
167
286
|
}
|
|
168
|
-
|
|
287
|
+
const files = usage?.status === "ready" ? usage.result.files : [];
|
|
288
|
+
return html`
|
|
289
|
+
<div class="media-usage">
|
|
290
|
+
<h4 class="media-usage-title">Used by</h4>
|
|
291
|
+
<p class="media-usage-headline">${headline}</p>
|
|
292
|
+
${files.length === 0 ? nothing : html`<ul class="media-usage-list">
|
|
293
|
+
${files.map((file) => html`<li>
|
|
294
|
+
<button
|
|
295
|
+
type="button"
|
|
296
|
+
class="media-usage-link"
|
|
297
|
+
@click=${() => {
|
|
298
|
+
openDocument(file.path);
|
|
299
|
+
}}
|
|
300
|
+
>
|
|
301
|
+
${file.path}
|
|
302
|
+
</button>
|
|
303
|
+
<span class="media-usage-count">${file.count}</span>
|
|
304
|
+
</li>`)}
|
|
305
|
+
</ul>`}
|
|
306
|
+
</div>
|
|
307
|
+
`;
|
|
308
|
+
}
|
|
309
|
+
async function openDocument(path) {
|
|
310
|
+
const { openFileInTab } = await import("./files-0cratsr0.js");
|
|
311
|
+
await openFileInTab(path);
|
|
169
312
|
}
|
|
170
|
-
function
|
|
171
|
-
|
|
172
|
-
|
|
313
|
+
function renderMediaMode(surface, tab) {
|
|
314
|
+
const { paneId, wrap: canvasWrap } = surface;
|
|
315
|
+
if (mediaPaneMounted(paneId, tab)) {
|
|
316
|
+
return;
|
|
173
317
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
318
|
+
detachMediaPane(paneId);
|
|
319
|
+
const scope = effectScope();
|
|
320
|
+
const panel = { paneId, scope, tabId: tab.id, wrap: canvasWrap };
|
|
321
|
+
_active.set(paneId, panel);
|
|
322
|
+
const path = tab.documentPath ?? "";
|
|
323
|
+
const redraw = () => {
|
|
324
|
+
if (activeIn(paneId) === panel) {
|
|
325
|
+
draw();
|
|
177
326
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
327
|
+
};
|
|
328
|
+
const draw = () => {
|
|
329
|
+
const meta = peekMediaMeta(path);
|
|
330
|
+
const usage = peekMediaUsages(path);
|
|
331
|
+
if (meta === null) {
|
|
332
|
+
loadMediaMeta(path).then(redraw);
|
|
181
333
|
}
|
|
182
|
-
|
|
183
|
-
|
|
334
|
+
if (usage === null || usage.status === "pending") {
|
|
335
|
+
loadMediaUsages(path).then(redraw);
|
|
184
336
|
}
|
|
185
|
-
|
|
186
|
-
|
|
337
|
+
render(html`
|
|
338
|
+
<div class="media-viewer" data-jx-region=${paneRegion(paneId, "media")}>
|
|
339
|
+
<div class="media-stage">${assetTpl(path, previewFileSrc(path), redraw)}</div>
|
|
340
|
+
<div class="media-details">
|
|
341
|
+
<h3 class="media-name">${path.split("/").pop()}</h3>
|
|
342
|
+
${factsTpl(path, meta)} ${refTpl(path)} ${usageTpl(usage)}
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
`, canvasWrap);
|
|
346
|
+
};
|
|
347
|
+
scope.run(() => {
|
|
348
|
+
effect(() => {
|
|
349
|
+
if (activeIn(paneId) !== panel) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
tab.documentPath;
|
|
353
|
+
draw();
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/media/media-open.ts
|
|
359
|
+
var MEDIA_STUB_DOCUMENT = { children: [], tagName: "div" };
|
|
360
|
+
function isViewableMedia(path) {
|
|
361
|
+
return isMediaFile(path);
|
|
362
|
+
}
|
|
363
|
+
function mediaTabModes(path) {
|
|
364
|
+
return extensionOf(path) === ".svg" ? [MEDIA_MODE, "source"] : [MEDIA_MODE];
|
|
365
|
+
}
|
|
366
|
+
function openMediaTab(path) {
|
|
367
|
+
const existing = workspace.tabs.get(path);
|
|
368
|
+
if (existing) {
|
|
369
|
+
activateTab(path);
|
|
370
|
+
return existing;
|
|
371
|
+
}
|
|
372
|
+
return openTab({
|
|
373
|
+
capabilities: { modes: mediaTabModes(path) },
|
|
374
|
+
document: structuredClone(MEDIA_STUB_DOCUMENT),
|
|
375
|
+
documentPath: path,
|
|
376
|
+
id: path,
|
|
377
|
+
sourceFormat: null
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/format/format-choices.ts
|
|
382
|
+
var DOCUMENT_KINDS = ["page", "component"];
|
|
383
|
+
var DOCUMENT_ROOTS = { components: "component", pages: "page" };
|
|
384
|
+
function normalize(path) {
|
|
385
|
+
return path.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
386
|
+
}
|
|
387
|
+
function documentRootOf(path) {
|
|
388
|
+
const lower = normalize(path).toLowerCase();
|
|
389
|
+
for (const [dir, kind] of Object.entries(DOCUMENT_ROOTS)) {
|
|
390
|
+
if (lower.startsWith(`${dir}/`)) {
|
|
391
|
+
return kind;
|
|
187
392
|
}
|
|
188
|
-
|
|
189
|
-
|
|
393
|
+
}
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
function declaresDocumentKind(kinds) {
|
|
397
|
+
return DOCUMENT_KINDS.some((kind) => kinds.includes(kind));
|
|
398
|
+
}
|
|
399
|
+
function isLayoutPath(path) {
|
|
400
|
+
const declared = projectState?.projectConfig?.layout;
|
|
401
|
+
if (typeof declared !== "string") {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
return normalize(declared).toLowerCase() === normalize(path).toLowerCase();
|
|
405
|
+
}
|
|
406
|
+
function creationFormats(kind) {
|
|
407
|
+
const rows = [{ ext: ".json", label: "JSON (.json)" }];
|
|
408
|
+
for (const ext of documentExtensions(kind)) {
|
|
409
|
+
const reader = formatByExtension(ext, "parse");
|
|
410
|
+
if (reader && formatByExtension(ext, "serialize")) {
|
|
411
|
+
rows.push({ ext, label: `${reader.name} (${ext})` });
|
|
190
412
|
}
|
|
191
413
|
}
|
|
414
|
+
return rows;
|
|
192
415
|
}
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
416
|
+
function knownDocumentExtensions() {
|
|
417
|
+
return new Set([".json", ...getFormats().flatMap((format) => format.extensions)]);
|
|
418
|
+
}
|
|
419
|
+
function convertTargets(path) {
|
|
420
|
+
if (path === null || path === undefined || path === "") {
|
|
421
|
+
return [];
|
|
422
|
+
}
|
|
423
|
+
const root = documentRootOf(path);
|
|
424
|
+
if (root === null || isLayoutPath(path) || collectionForFile(path)) {
|
|
425
|
+
return [];
|
|
426
|
+
}
|
|
427
|
+
const source = formatForPath(path);
|
|
428
|
+
const readable = source ? Boolean(source.capabilities.parse) && declaresDocumentKind(source.documentKinds) : normalize(path).toLowerCase().endsWith(".json");
|
|
429
|
+
if (!readable) {
|
|
430
|
+
return [];
|
|
197
431
|
}
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
432
|
+
const rows = [];
|
|
433
|
+
if (source) {
|
|
434
|
+
rows.push({ ext: ".json", label: "JSON (.json)" });
|
|
435
|
+
}
|
|
436
|
+
for (const ext of documentExtensions()) {
|
|
437
|
+
const writer = formatByExtension(ext, "serialize");
|
|
438
|
+
if (!writer || writer.name === source?.name || !declaresDocumentKind(writer.documentKinds) || !writer.documentKinds.includes(root)) {
|
|
439
|
+
continue;
|
|
205
440
|
}
|
|
441
|
+
rows.push({ ext, label: `${writer.name} (${ext})` });
|
|
206
442
|
}
|
|
207
|
-
return
|
|
443
|
+
return rows;
|
|
208
444
|
}
|
|
209
|
-
function
|
|
210
|
-
const
|
|
211
|
-
|
|
445
|
+
function convertTargetExtensions() {
|
|
446
|
+
const exts = new Set([".json"]);
|
|
447
|
+
for (const format of getFormats()) {
|
|
448
|
+
if (!format.capabilities.serialize || !declaresDocumentKind(format.documentKinds)) {
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
for (const ext of format.extensions) {
|
|
452
|
+
exts.add(ext);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return [...exts].toSorted();
|
|
212
456
|
}
|
|
213
457
|
|
|
214
458
|
// src/recent-projects.ts
|
|
@@ -330,12 +574,21 @@ async function loadDirectory(dirPath) {
|
|
|
330
574
|
}
|
|
331
575
|
try {
|
|
332
576
|
const platform = getPlatform();
|
|
333
|
-
const entries = await
|
|
577
|
+
const [entries] = await Promise.all([
|
|
578
|
+
platform.listDirectory(dirPath),
|
|
579
|
+
ensureIgnoreLayers(dirPath)
|
|
580
|
+
]);
|
|
334
581
|
projectState.dirs.set(dirPath, entries);
|
|
335
582
|
} catch {
|
|
336
583
|
projectState.dirs.set(dirPath, []);
|
|
337
584
|
}
|
|
338
585
|
}
|
|
586
|
+
function showIgnoredFiles() {
|
|
587
|
+
return readStoredSetting(SETTINGS.showIgnoredFiles) === "true";
|
|
588
|
+
}
|
|
589
|
+
function setShowIgnoredFiles(show) {
|
|
590
|
+
setSetting(SETTINGS.showIgnoredFiles, show ? "true" : "");
|
|
591
|
+
}
|
|
339
592
|
async function loadProject() {
|
|
340
593
|
try {
|
|
341
594
|
const platform = getPlatform();
|
|
@@ -347,6 +600,7 @@ async function loadProject() {
|
|
|
347
600
|
refreshFormats();
|
|
348
601
|
loadFormats();
|
|
349
602
|
refreshExtensionUi(platform);
|
|
603
|
+
resetIgnoreCache();
|
|
350
604
|
setProjectState({
|
|
351
605
|
dirs: new Map,
|
|
352
606
|
expanded: new Set,
|
|
@@ -365,7 +619,11 @@ async function loadProject() {
|
|
|
365
619
|
if (info.isSiteProject) {
|
|
366
620
|
addRecentProject(requireProjectState().name, meta.root);
|
|
367
621
|
await autoSyncProjectOnOpen();
|
|
368
|
-
await ensureDependenciesInstalled()
|
|
622
|
+
if (await ensureDependenciesInstalled()) {
|
|
623
|
+
refreshFormats();
|
|
624
|
+
await loadFormats();
|
|
625
|
+
refreshExtensionUi(platform);
|
|
626
|
+
}
|
|
369
627
|
await loadDirectory(".");
|
|
370
628
|
await loadComponentRegistry();
|
|
371
629
|
await openLastSessionOrHome();
|
|
@@ -387,9 +645,11 @@ async function openProject({
|
|
|
387
645
|
document: { children: [], tagName: "div" },
|
|
388
646
|
id: "initial"
|
|
389
647
|
});
|
|
648
|
+
disarmPreviewOverlay();
|
|
390
649
|
refreshFormats();
|
|
391
650
|
loadFormats();
|
|
392
651
|
refreshExtensionUi(platform);
|
|
652
|
+
resetIgnoreCache();
|
|
393
653
|
setProjectState({
|
|
394
654
|
...projectState,
|
|
395
655
|
dirs: new Map,
|
|
@@ -403,7 +663,11 @@ async function openProject({
|
|
|
403
663
|
});
|
|
404
664
|
setWorkspaceProject(handle.root, config);
|
|
405
665
|
await autoSyncProjectOnOpen();
|
|
406
|
-
await ensureDependenciesInstalled()
|
|
666
|
+
if (await ensureDependenciesInstalled()) {
|
|
667
|
+
refreshFormats();
|
|
668
|
+
await loadFormats();
|
|
669
|
+
refreshExtensionUi(platform);
|
|
670
|
+
}
|
|
407
671
|
await loadDirectory(".");
|
|
408
672
|
await loadComponentRegistry();
|
|
409
673
|
const conventionalDirs = new Set([
|
|
@@ -549,6 +813,7 @@ function renderFilesTemplate({
|
|
|
549
813
|
<sp-button variant="accent" size="s" @click=${openProjectFn}>Open Project</sp-button>
|
|
550
814
|
</div>`;
|
|
551
815
|
}
|
|
816
|
+
const showingIgnored = showIgnoredFiles();
|
|
552
817
|
return html`
|
|
553
818
|
${projectState.isSiteProject ? html`
|
|
554
819
|
<div class="project-header">
|
|
@@ -571,6 +836,7 @@ function renderFilesTemplate({
|
|
|
571
836
|
label="Refresh"
|
|
572
837
|
@click=${async () => {
|
|
573
838
|
requireProjectState().dirs.clear();
|
|
839
|
+
resetIgnoreCache();
|
|
574
840
|
await loadDirectory(".");
|
|
575
841
|
for (const dir of requireProjectState().expanded) {
|
|
576
842
|
await loadDirectory(dir);
|
|
@@ -580,6 +846,17 @@ function renderFilesTemplate({
|
|
|
580
846
|
>
|
|
581
847
|
<sp-icon-refresh slot="icon"></sp-icon-refresh>
|
|
582
848
|
</sp-action-button>
|
|
849
|
+
<sp-action-button
|
|
850
|
+
size="xs"
|
|
851
|
+
label=${showingIgnored ? "Hide ignored files" : "Show ignored files"}
|
|
852
|
+
?selected=${showingIgnored}
|
|
853
|
+
@click=${() => {
|
|
854
|
+
setShowIgnoredFiles(!showingIgnored);
|
|
855
|
+
renderLeftPanel();
|
|
856
|
+
}}
|
|
857
|
+
>
|
|
858
|
+
${showingIgnored ? html`<sp-icon-visibility slot="icon"></sp-icon-visibility>` : html`<sp-icon-visibility-off slot="icon"></sp-icon-visibility-off>`}
|
|
859
|
+
</sp-action-button>
|
|
583
860
|
</sp-action-group>
|
|
584
861
|
<sp-search
|
|
585
862
|
size="s"
|
|
@@ -645,8 +922,9 @@ function collectFileRows(dirPath, depth, rows, ctx, i18n) {
|
|
|
645
922
|
}
|
|
646
923
|
return a.name.localeCompare(b.name);
|
|
647
924
|
});
|
|
925
|
+
const visible = showIgnoredFiles() ? sorted : sorted.filter((e) => !isIgnoredEntry(dirPath, e.path, e.type === "directory"));
|
|
648
926
|
const query = requireProjectState().searchQuery.toLowerCase();
|
|
649
|
-
const filtered = query ?
|
|
927
|
+
const filtered = query ? visible.filter((e) => e.type === "directory" || e.name.toLowerCase().includes(query)) : visible;
|
|
650
928
|
for (const [index, entry] of filtered.entries()) {
|
|
651
929
|
const isDir = entry.type === "directory";
|
|
652
930
|
const isExpanded = isDir && requireProjectState().expanded.has(entry.path);
|
|
@@ -889,7 +1167,7 @@ function pickAndUploadTo(dir, renderLeftPanel) {
|
|
|
889
1167
|
const input = document.createElement("input");
|
|
890
1168
|
input.type = "file";
|
|
891
1169
|
input.multiple = true;
|
|
892
|
-
input.accept =
|
|
1170
|
+
input.accept = uploadAccept();
|
|
893
1171
|
input.addEventListener("change", () => {
|
|
894
1172
|
if (input.files?.length) {
|
|
895
1173
|
uploadFilesToDir(input.files, dir, renderLeftPanel);
|
|
@@ -1023,6 +1301,7 @@ async function moveFileEntry(oldPath, newPath, renderLeftPanel) {
|
|
|
1023
1301
|
markLocalMutation(oldPath, newPath);
|
|
1024
1302
|
try {
|
|
1025
1303
|
const report = await platform.renameFile(oldPath, newPath);
|
|
1304
|
+
invalidateUsages();
|
|
1026
1305
|
for (const [id] of workspace.tabs.entries()) {
|
|
1027
1306
|
if (id === oldPath) {
|
|
1028
1307
|
renameTab(oldPath, newPath, newPath);
|
|
@@ -1042,7 +1321,7 @@ async function moveFileEntry(oldPath, newPath, renderLeftPanel) {
|
|
|
1042
1321
|
}
|
|
1043
1322
|
reloadRewrittenTabs(report, newPath);
|
|
1044
1323
|
renderLeftPanel();
|
|
1045
|
-
|
|
1324
|
+
notifyMoveOutcome(`Moved to ${newPath}`, report, newPath);
|
|
1046
1325
|
} catch (error) {
|
|
1047
1326
|
notify.error(`Could not move ${oldPath}.`, {
|
|
1048
1327
|
detail: errorMessage(error),
|
|
@@ -1066,13 +1345,18 @@ function dismissFileContextMenu() {
|
|
|
1066
1345
|
function fileRowFacts(entry) {
|
|
1067
1346
|
const facts = {};
|
|
1068
1347
|
if (entry.type === "directory") {
|
|
1069
|
-
const collection =
|
|
1070
|
-
if (collection) {
|
|
1348
|
+
const collection = collectionForDirectory(entry.path);
|
|
1349
|
+
if (collection?.isSourceRoot === true && !collection.fileBacked) {
|
|
1071
1350
|
facts.name = collection.name;
|
|
1072
1351
|
}
|
|
1073
|
-
|
|
1352
|
+
return facts;
|
|
1353
|
+
}
|
|
1354
|
+
if (collectionOfPath(entry.path)) {
|
|
1074
1355
|
facts.path = entry.path;
|
|
1075
1356
|
}
|
|
1357
|
+
if (convertTargets(entry.path).length > 0) {
|
|
1358
|
+
facts.source = entry.path;
|
|
1359
|
+
}
|
|
1076
1360
|
return facts;
|
|
1077
1361
|
}
|
|
1078
1362
|
function placedFileItems(entry) {
|
|
@@ -1182,40 +1466,122 @@ function showFileContextMenu(e, entry, ctx) {
|
|
|
1182
1466
|
});
|
|
1183
1467
|
}
|
|
1184
1468
|
var BLANK_DOCUMENT = JSON.stringify({ children: [{ children: [], tagName: "p" }], tagName: "div" }, null, 2);
|
|
1469
|
+
var OTHER_FORMAT = "__other__";
|
|
1470
|
+
function slugify(input) {
|
|
1471
|
+
return input.trim().toLowerCase().replaceAll(/\s+/g, "-").replaceAll(/[^a-z\d-]/g, "");
|
|
1472
|
+
}
|
|
1473
|
+
function extensionOfName(name) {
|
|
1474
|
+
const dot = name.lastIndexOf(".");
|
|
1475
|
+
return dot > 0 ? name.slice(dot) : "";
|
|
1476
|
+
}
|
|
1477
|
+
function formatRowsFor(choice) {
|
|
1478
|
+
const rows = choice.kind === "locked" ? [
|
|
1479
|
+
{
|
|
1480
|
+
ext: choice.ext,
|
|
1481
|
+
label: `${formatByExtension(choice.ext)?.name ?? choice.ext} (${choice.ext})`
|
|
1482
|
+
}
|
|
1483
|
+
] : creationFormats(choice.docKind);
|
|
1484
|
+
return [
|
|
1485
|
+
...rows.map((row) => ({ label: row.label, value: row.ext })),
|
|
1486
|
+
{ dividerBefore: true, label: "Other…", value: OTHER_FORMAT }
|
|
1487
|
+
];
|
|
1488
|
+
}
|
|
1489
|
+
function initialPickFor(choice, rows, suggested) {
|
|
1490
|
+
const stated = choice.kind === "choose" ? choice.defaultExt : choice.ext;
|
|
1491
|
+
if (stated !== undefined && rows.some((row) => row.value === stated)) {
|
|
1492
|
+
return stated;
|
|
1493
|
+
}
|
|
1494
|
+
const fromPrefill = extensionOfName(suggested);
|
|
1495
|
+
if (fromPrefill !== "" && rows.some((row) => row.value === fromPrefill)) {
|
|
1496
|
+
return fromPrefill;
|
|
1497
|
+
}
|
|
1498
|
+
return rows[0]?.value ?? OTHER_FORMAT;
|
|
1499
|
+
}
|
|
1185
1500
|
async function createFileIn(request) {
|
|
1186
|
-
const { dir,
|
|
1501
|
+
const { dir, format: choice, source = "Files" } = request;
|
|
1187
1502
|
await loadFormats();
|
|
1188
1503
|
let taken = new Set;
|
|
1189
1504
|
try {
|
|
1190
1505
|
const listing = await getPlatform().listDirectory(dir);
|
|
1191
|
-
taken = new Set(listing.map((entry) => entry.name));
|
|
1506
|
+
taken = new Set(listing.map((entry) => entry.name.toLowerCase()));
|
|
1192
1507
|
} catch {}
|
|
1193
|
-
const
|
|
1508
|
+
const picker = choice !== undefined && choice.kind !== "fixed" ? choice : null;
|
|
1509
|
+
const rows = picker === null ? null : formatRowsFor(picker);
|
|
1510
|
+
const initialPick = picker === null || rows === null ? "" : initialPickFor(picker, rows, request.suggestedName ?? "");
|
|
1511
|
+
const fileNameFor = (input, picked2) => {
|
|
1512
|
+
const trimmed = input.trim();
|
|
1513
|
+
if (choice === undefined || picked2 === OTHER_FORMAT) {
|
|
1514
|
+
return trimmed;
|
|
1515
|
+
}
|
|
1516
|
+
if (choice.kind === "fixed") {
|
|
1517
|
+
const slug = slugify(trimmed);
|
|
1518
|
+
return slug === "" ? "" : `${slug}${choice.ext}`;
|
|
1519
|
+
}
|
|
1520
|
+
return trimmed.toLowerCase().endsWith(picked2.toLowerCase()) ? trimmed : `${trimmed}${picked2}`;
|
|
1521
|
+
};
|
|
1522
|
+
const known = knownDocumentExtensions();
|
|
1523
|
+
const validate = (value, picked2) => {
|
|
1524
|
+
const trimmed = value.trim();
|
|
1525
|
+
if (!trimmed) {
|
|
1526
|
+
return choice?.kind === "fixed" ? "Enter a name." : "Enter a file name.";
|
|
1527
|
+
}
|
|
1528
|
+
if (choice?.kind === "fixed" && slugify(trimmed) === "") {
|
|
1529
|
+
return "Enter at least one letter or number.";
|
|
1530
|
+
}
|
|
1531
|
+
const normalized = trimmed.replaceAll("\\", "/");
|
|
1532
|
+
if (normalized.startsWith("/") || normalized.endsWith("/")) {
|
|
1533
|
+
return "Enter a name, not a path that starts or ends with a slash.";
|
|
1534
|
+
}
|
|
1535
|
+
if (normalized.split("/").includes("..")) {
|
|
1536
|
+
return "A name cannot step outside the destination folder.";
|
|
1537
|
+
}
|
|
1538
|
+
if (normalized.includes("/") && choice !== undefined && picked2 !== OTHER_FORMAT) {
|
|
1539
|
+
return `Pick Other… to create a file in a subfolder of ${dir === "." ? "the project root" : dir}.`;
|
|
1540
|
+
}
|
|
1541
|
+
const typedExt = extensionOfName(normalized);
|
|
1542
|
+
if (picked2 !== "" && picked2 !== OTHER_FORMAT && typedExt !== "" && typedExt.toLowerCase() !== picked2.toLowerCase() && known.has(typedExt.toLowerCase())) {
|
|
1543
|
+
const label = rows?.find((row) => row.value === picked2)?.label ?? picked2;
|
|
1544
|
+
return `You picked ${label}; this name ends in ${typedExt}.`;
|
|
1545
|
+
}
|
|
1546
|
+
if (choice?.kind === "locked" && picked2 === OTHER_FORMAT) {
|
|
1547
|
+
const foreign = typedExt !== "" && typedExt.toLowerCase() !== choice.ext.toLowerCase();
|
|
1548
|
+
if (foreign && known.has(typedExt.toLowerCase())) {
|
|
1549
|
+
return choice.because;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
const candidate = fileNameFor(value, picked2);
|
|
1553
|
+
return taken.has(candidate.toLowerCase()) ? `${candidate} already exists in ${dir}/.` : "";
|
|
1554
|
+
};
|
|
1555
|
+
let picked = initialPick;
|
|
1194
1556
|
const entered = await showPromptDialog(request.title ?? "New File", {
|
|
1557
|
+
...rows === null ? {} : {
|
|
1558
|
+
choice: {
|
|
1559
|
+
initial: initialPick,
|
|
1560
|
+
label: "Format",
|
|
1561
|
+
onChange: (next) => {
|
|
1562
|
+
picked = next;
|
|
1563
|
+
},
|
|
1564
|
+
options: () => rows
|
|
1565
|
+
}
|
|
1566
|
+
},
|
|
1195
1567
|
confirmLabel: "Create",
|
|
1196
1568
|
message: dir === "." ? "Creating in the project root." : `Creating in ${dir}/`,
|
|
1197
1569
|
...request.suggestedName === undefined ? {} : { placeholder: request.suggestedName },
|
|
1198
|
-
select: "stem",
|
|
1199
|
-
validate
|
|
1200
|
-
if (!value.trim()) {
|
|
1201
|
-
return ext === undefined ? "Enter a file name." : "Enter a name.";
|
|
1202
|
-
}
|
|
1203
|
-
const candidate = fileNameFor(value);
|
|
1204
|
-
if (!candidate || candidate === ext) {
|
|
1205
|
-
return "Enter at least one letter or number.";
|
|
1206
|
-
}
|
|
1207
|
-
return taken.has(candidate) ? `${candidate} already exists in ${dir}/.` : "";
|
|
1208
|
-
},
|
|
1570
|
+
select: rows === null ? "stem" : "all",
|
|
1571
|
+
validate,
|
|
1209
1572
|
value: request.suggestedName ?? "untitled.json"
|
|
1210
1573
|
});
|
|
1211
1574
|
if (!entered) {
|
|
1212
1575
|
return null;
|
|
1213
1576
|
}
|
|
1214
|
-
const fileName = fileNameFor(entered);
|
|
1577
|
+
const fileName = fileNameFor(entered, picked);
|
|
1215
1578
|
const path = dir === "." ? fileName : `${dir}/${fileName}`;
|
|
1216
1579
|
markLocalMutation(path);
|
|
1217
1580
|
const format = formatForPath(fileName);
|
|
1218
|
-
const
|
|
1581
|
+
const suppliedBody = typeof request.content === "function" ? await request.content(extensionOfName(fileName), fileName) : request.content;
|
|
1582
|
+
const chosenAsDocument = choice !== undefined && picked !== OTHER_FORMAT;
|
|
1583
|
+
const content = suppliedBody ?? format?.studio?.newFileTemplate ?? (format ? "" : fileName.toLowerCase().endsWith(".json") ? chosenAsDocument ? BLANK_DOCUMENT : `{}
|
|
1584
|
+
` : "");
|
|
1219
1585
|
try {
|
|
1220
1586
|
await getPlatform().writeFile(path, content);
|
|
1221
1587
|
await loadDirectory(dir);
|
|
@@ -1231,7 +1597,32 @@ async function createFileIn(request) {
|
|
|
1231
1597
|
}
|
|
1232
1598
|
}
|
|
1233
1599
|
async function createNewFile(dirPath, renderLeftPanel) {
|
|
1234
|
-
|
|
1600
|
+
await loadFormats();
|
|
1601
|
+
const collection = collectionForDirectory(dirPath);
|
|
1602
|
+
if (collection?.unresolvedFormat != null) {
|
|
1603
|
+
notify.error(`New files in ${dirPath}/ cannot be constrained to the collection's format.`, {
|
|
1604
|
+
detail: `The "${collection.name}" content type declares format "${collection.unresolvedFormat}", ` + "which no installed extension provides. Install the extension that supplies it, or correct " + "the name in Project Settings › Content Types.",
|
|
1605
|
+
path: dirPath,
|
|
1606
|
+
source: "Files"
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
const constrained = collection?.ext != null && collection.unresolvedFormat === null;
|
|
1610
|
+
const seedable = constrained && collection.isSourceRoot && collection.def.schema !== undefined;
|
|
1611
|
+
let created;
|
|
1612
|
+
if (seedable) {
|
|
1613
|
+
const { createEntry } = await import("./entry-commands-6z6bhxg0.js");
|
|
1614
|
+
created = await createEntry(collection.name, { dir: dirPath });
|
|
1615
|
+
} else {
|
|
1616
|
+
created = await createFileIn({
|
|
1617
|
+
dir: dirPath,
|
|
1618
|
+
format: constrained && collection.ext !== null ? {
|
|
1619
|
+
because: `${collection.name} entries are ${collection.ext} files, so a document of another format here would not be one.`,
|
|
1620
|
+
ext: collection.ext,
|
|
1621
|
+
kind: "locked"
|
|
1622
|
+
} : { defaultExt: ".json", kind: "choose" },
|
|
1623
|
+
suggestedName: "untitled"
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1235
1626
|
if (created !== null) {
|
|
1236
1627
|
renderLeftPanel();
|
|
1237
1628
|
}
|
|
@@ -1257,6 +1648,20 @@ function renameStatus(newName, report) {
|
|
|
1257
1648
|
}
|
|
1258
1649
|
return `Renamed to ${newName}`;
|
|
1259
1650
|
}
|
|
1651
|
+
function notifyMoveOutcome(headline, report, path) {
|
|
1652
|
+
const stuck = report.errors ?? [];
|
|
1653
|
+
if (stuck.length === 0) {
|
|
1654
|
+
notify.success(headline);
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
const files = stuck.length === 1 ? "1 file" : `${stuck.length} files`;
|
|
1658
|
+
notify.warn(`${headline} — references in ${files} could not be updated`, {
|
|
1659
|
+
detail: stuck.map((e) => `${e.path}: ${e.error}`).join(`
|
|
1660
|
+
`),
|
|
1661
|
+
path,
|
|
1662
|
+
source: "Files"
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1260
1665
|
function reloadRewrittenTabs(report, skipPath) {
|
|
1261
1666
|
for (const f of report.references?.files ?? []) {
|
|
1262
1667
|
if (f.path !== skipPath && workspace.tabs.has(f.path)) {
|
|
@@ -1264,29 +1669,40 @@ function reloadRewrittenTabs(report, skipPath) {
|
|
|
1264
1669
|
}
|
|
1265
1670
|
}
|
|
1266
1671
|
}
|
|
1672
|
+
function parentDirOf(path) {
|
|
1673
|
+
const normalized = path.replaceAll("\\", "/");
|
|
1674
|
+
return normalized.includes("/") ? normalized.slice(0, normalized.lastIndexOf("/")) : ".";
|
|
1675
|
+
}
|
|
1676
|
+
async function settleRename(from, to, report) {
|
|
1677
|
+
invalidateUsages();
|
|
1678
|
+
const fromDir = parentDirOf(from);
|
|
1679
|
+
const toDir = parentDirOf(to);
|
|
1680
|
+
await loadDirectory(fromDir);
|
|
1681
|
+
if (toDir !== fromDir) {
|
|
1682
|
+
await loadDirectory(toDir);
|
|
1683
|
+
}
|
|
1684
|
+
if (requireProjectState().selectedPath === from) {
|
|
1685
|
+
requireProjectState().selectedPath = to;
|
|
1686
|
+
}
|
|
1687
|
+
reloadRewrittenTabs(report, to);
|
|
1688
|
+
}
|
|
1267
1689
|
async function renameFile(entry, renderLeftPanel) {
|
|
1268
1690
|
const newName = await showRenameFileDialog(entry.name, entry.path);
|
|
1269
1691
|
if (!newName || newName === entry.name) {
|
|
1270
1692
|
return;
|
|
1271
1693
|
}
|
|
1272
|
-
const
|
|
1273
|
-
const parentDirPath = entryPath.includes("/") ? entryPath.slice(0, entryPath.lastIndexOf("/")) : ".";
|
|
1694
|
+
const parentDirPath = parentDirOf(entry.path);
|
|
1274
1695
|
const newPath = parentDirPath === "." ? newName : `${parentDirPath}/${newName}`;
|
|
1275
1696
|
markLocalMutation(entry.path, newPath);
|
|
1276
1697
|
try {
|
|
1277
1698
|
const platform = getPlatform();
|
|
1278
1699
|
const report = await platform.renameFile(entry.path, newPath);
|
|
1279
|
-
invalidateUsages();
|
|
1280
|
-
await loadDirectory(parentDirPath);
|
|
1281
|
-
if (requireProjectState().selectedPath === entry.path) {
|
|
1282
|
-
requireProjectState().selectedPath = newPath;
|
|
1283
|
-
}
|
|
1284
1700
|
if (workspace.tabs.has(entry.path)) {
|
|
1285
1701
|
renameTab(entry.path, newPath, newPath);
|
|
1286
1702
|
}
|
|
1287
|
-
|
|
1703
|
+
await settleRename(entry.path, newPath, report);
|
|
1288
1704
|
renderLeftPanel();
|
|
1289
|
-
|
|
1705
|
+
notifyMoveOutcome(renameStatus(newName, report), report, newPath);
|
|
1290
1706
|
} catch (error) {
|
|
1291
1707
|
notify.error(`Could not rename ${entry.name}.`, {
|
|
1292
1708
|
detail: errorMessage(error),
|
|
@@ -1343,6 +1759,18 @@ async function openFileInTab(path, opts = {}) {
|
|
|
1343
1759
|
return;
|
|
1344
1760
|
}
|
|
1345
1761
|
}
|
|
1762
|
+
if (isViewableMedia(path)) {
|
|
1763
|
+
openMediaTab(path);
|
|
1764
|
+
if (follows) {
|
|
1765
|
+
requireProjectState().selectedPath = path;
|
|
1766
|
+
}
|
|
1767
|
+
trackRecentFile({
|
|
1768
|
+
name: path.split("/").pop() || path,
|
|
1769
|
+
path,
|
|
1770
|
+
root: requireProjectState().projectRoot
|
|
1771
|
+
});
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1346
1774
|
if (path.toLowerCase().endsWith(".csv")) {
|
|
1347
1775
|
try {
|
|
1348
1776
|
await openCsvGridTab(path);
|
|
@@ -1365,6 +1793,10 @@ async function openFileInTab(path, opts = {}) {
|
|
|
1365
1793
|
try {
|
|
1366
1794
|
const content = await platform.readFile(path);
|
|
1367
1795
|
if (!content) {
|
|
1796
|
+
await loadFormats();
|
|
1797
|
+
if (!formatForPath(path) && !path.toLowerCase().endsWith(".json")) {
|
|
1798
|
+
throw noFormatError(path);
|
|
1799
|
+
}
|
|
1368
1800
|
return;
|
|
1369
1801
|
}
|
|
1370
1802
|
await loadFormats();
|
|
@@ -1465,7 +1897,7 @@ function registerFilesPanel() {
|
|
|
1465
1897
|
});
|
|
1466
1898
|
}
|
|
1467
1899
|
|
|
1468
|
-
export { ensureDependenciesInstalled,
|
|
1900
|
+
export { ensureDependenciesInstalled, mediaPaneMounted, detachMediaPane, renderMediaMode, convertTargets, convertTargetExtensions, hydrateRecentProjects, getRecentProjects, addRecentProject, removeRecentProject, clearRecentProjects, getRecentFiles, trackRecentFile, loadDirectory, showIgnoredFiles, setShowIgnoredFiles, loadProject, openProject, initProjectRepo, findHomePage, openHomePage, openLastSessionOrHome, renderFilesTemplate, FILE_ROW_HEIGHT, isFileDrag, uploadFilesToDir, pickAndUploadTo, registerFileTreeDnD, OTHER_FORMAT, createFileIn, notifyMoveOutcome, parentDirOf, settleRename, openFileInTab, openFileInPane, reloadCleanTab, reloadFileInTab, registerFilesPanel };
|
|
1469
1901
|
|
|
1470
|
-
//# debugId=
|
|
1471
|
-
//# sourceMappingURL=studio-
|
|
1902
|
+
//# debugId=3C1BF8083E5F1C8564756E2164756E21
|
|
1903
|
+
//# sourceMappingURL=studio-5rywrkxz.js.map
|