@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.
Files changed (208) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/Overlay.dev-723bv0df.js +23 -0
  3. package/dist/chunks/cf-settings-45fgyx8y.js +21 -0
  4. package/dist/chunks/{components-z6cnkyy1.js → components-zmx10t62.js} +6 -5
  5. package/dist/chunks/content-source-t88vb2dr.js +49 -0
  6. package/dist/chunks/{convert-to-repeater-k10dvcc7.js → convert-to-repeater-dhw1nrz9.js} +27 -18
  7. package/dist/chunks/entry-commands-6z6bhxg0.js +46 -0
  8. package/dist/chunks/{extension-sections-0ada0xcw.js → extension-sections-3ydgjbdy.js} +32 -23
  9. package/dist/chunks/file-ops-rskmhxyq.js +48 -0
  10. package/dist/chunks/files-0cratsr0.js +92 -0
  11. package/dist/chunks/{format-host-wewba4nq.js → format-host-tgcmfs4p.js} +3 -3
  12. package/dist/chunks/fs-events-hrrg328g.js +21 -0
  13. package/dist/chunks/{git-panel-2dh1aw50.js → git-panel-0yywyk76.js} +21 -15
  14. package/dist/chunks/{jx-validate-jj9rnt4n.js → jx-validate-8q2g05x1.js} +6 -4
  15. package/dist/chunks/layers-panel-z3tqe5cd.js +67 -0
  16. package/dist/chunks/layers-q75tj2mf.js +45 -0
  17. package/dist/chunks/lit-html-j055mkh8.js +22 -0
  18. package/dist/chunks/monaco-buffer-dqw0xxpx.js +25 -0
  19. package/dist/chunks/{monaco-setup-a5wkmbgh.js → monaco-setup-rws7k4br.js} +4 -4
  20. package/dist/chunks/notify-yjm79n4s.js +30 -0
  21. package/dist/chunks/parse-24d0gay3.js +19 -0
  22. package/dist/chunks/platform-ba1j1gbh.js +16 -0
  23. package/dist/chunks/publish-panel-54jvhskq.js +28 -0
  24. package/dist/chunks/quick-search-cgfmjwq5.js +65 -0
  25. package/dist/chunks/references-3qx8fkyp.js +29 -0
  26. package/dist/chunks/right-panel-cqp8bc4v.js +46 -0
  27. package/dist/chunks/sp-overlay.dev-yztmtrs1.js +18 -0
  28. package/dist/chunks/sp-popover.dev-n2etmqdp.js +9 -0
  29. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +15 -0
  30. package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +15 -0
  31. package/dist/chunks/{sp-tray.dev-64v4pxw8.js → sp-tray.dev-tkbscm06.js} +5 -5
  32. package/dist/chunks/{studio-f5yyvqxv.js → studio-1hbqnt19.js} +37 -31
  33. package/dist/chunks/studio-2zkz8evn.js +3163 -0
  34. package/dist/chunks/{studio-0b6fs05q.js → studio-4pqqxbrt.js} +23 -15
  35. package/dist/chunks/{studio-kvfx9z2c.js → studio-4rzyrtjz.js} +70 -31
  36. package/dist/chunks/{studio-ef8t53vc.js → studio-5q69gfag.js} +60 -56
  37. package/dist/chunks/{studio-v2c5pmjj.js → studio-5rywrkxz.js} +565 -133
  38. package/dist/chunks/{studio-6kv3apa9.js → studio-68n67094.js} +25 -9
  39. package/dist/chunks/{studio-0rqqhrdy.js → studio-7nte2hj4.js} +2 -2
  40. package/dist/chunks/{studio-hyn3vhwr.js → studio-8swrjbny.js} +31 -18
  41. package/dist/chunks/studio-92ab2jqe.js +282 -0
  42. package/dist/chunks/{studio-sas7mt3k.js → studio-9ab8gqsm.js} +2 -2
  43. package/dist/chunks/{studio-28xc8ws4.js → studio-9c4k4vhv.js} +14 -10
  44. package/dist/chunks/studio-9n4mrmnb.js +184 -0
  45. package/dist/chunks/{studio-tr20m8g8.js → studio-9r6j5ev1.js} +37 -2
  46. package/dist/chunks/{studio-aweyr4v1.js → studio-ahjfdy6e.js} +9 -7
  47. package/dist/chunks/{studio-s519zc99.js → studio-bgxt93ga.js} +3 -3
  48. package/dist/chunks/{studio-26sv44br.js → studio-cb12yz9w.js} +8543 -8784
  49. package/dist/chunks/studio-cft9r4r7.js +119 -0
  50. package/dist/chunks/{studio-rqemfhz6.js → studio-eenfkt4e.js} +6 -6
  51. package/dist/chunks/studio-eesa1myv.js +498 -0
  52. package/dist/chunks/{studio-ay8wcr2b.js → studio-eqq1w638.js} +7 -9
  53. package/dist/chunks/{studio-ke244pam.js → studio-ex8zyp98.js} +51 -25
  54. package/dist/chunks/studio-gv8vvshc.js +118 -0
  55. package/dist/chunks/studio-hbtp0eh1.js +1315 -0
  56. package/dist/chunks/{studio-cz2j1c0g.js → studio-htsf0w6m.js} +75 -123
  57. package/dist/chunks/{studio-pyrw8h0w.js → studio-kjjsjak4.js} +528 -212
  58. package/dist/chunks/{studio-5x5774ak.js → studio-kryvsw6j.js} +3 -3
  59. package/dist/chunks/studio-kyh9avvv.js +28 -0
  60. package/dist/chunks/{studio-jnakhg87.js → studio-kyk2v92a.js} +14 -14
  61. package/dist/chunks/{studio-twsafr1e.js → studio-m3hwn7y1.js} +3 -3
  62. package/dist/chunks/{studio-tzx3xmvx.js → studio-mmv72a27.js} +8 -8
  63. package/dist/chunks/{studio-vhk5fmfv.js → studio-n8b9wqwy.js} +5 -5
  64. package/dist/chunks/{studio-cjm7fdjf.js → studio-p4ngc046.js} +8 -104
  65. package/dist/chunks/{studio-sccge2wf.js → studio-p8j86wag.js} +2 -2
  66. package/dist/chunks/{studio-v1va0vhd.js → studio-pdfjntbk.js} +75 -139
  67. package/dist/chunks/studio-q43a5y9h.js +394 -0
  68. package/dist/chunks/studio-q7v10cg2.js +106 -0
  69. package/dist/chunks/{studio-2w11grav.js → studio-qq6jym04.js} +3 -3
  70. package/dist/chunks/studio-r1r7afxx.js +1066 -0
  71. package/dist/chunks/{studio-3fk1ac9z.js → studio-rdx8jcxy.js} +4 -4
  72. package/dist/chunks/{studio-4mqb9a0j.js → studio-rn9ta2mz.js} +4 -4
  73. package/dist/chunks/studio-sf7zjgv1.js +91 -0
  74. package/dist/chunks/studio-t7qb9db8.js +665 -0
  75. package/dist/chunks/studio-tmc5emrw.js +8 -0
  76. package/dist/chunks/{studio-wdt9y92a.js → studio-txwkm6p9.js} +2 -2
  77. package/dist/chunks/{studio-dgj7gq44.js → studio-v38hmvx1.js} +7 -7
  78. package/dist/chunks/{studio-7ejemhej.js → studio-vadzgkrz.js} +6 -6
  79. package/dist/chunks/studio-wcy8trfx.js +263 -0
  80. package/dist/chunks/{studio-hb7c46jy.js → studio-wx5609xd.js} +21 -15
  81. package/dist/chunks/studio-xrapxwwc.js +1539 -0
  82. package/dist/chunks/{studio-ws6ef6js.js → studio-yxrkyv8a.js} +41 -29
  83. package/dist/chunks/{studio-xm3dbxvn.js → studio-zczps70q.js} +2 -2
  84. package/dist/chunks/workspace-xpres40v.js +89 -0
  85. package/dist/iframe-entry.js +450 -48
  86. package/dist/studio.js +2455 -1761
  87. package/package.json +16 -15
  88. package/src/browse/library-layouts.ts +3 -3
  89. package/src/browse/library-pane.ts +59 -5
  90. package/src/browse/library-preview.ts +19 -3
  91. package/src/canvas/asset-refs.ts +119 -0
  92. package/src/canvas/asset-resolve.ts +256 -0
  93. package/src/canvas/canvas-live-render.ts +23 -15
  94. package/src/canvas/canvas-render.ts +23 -1
  95. package/src/canvas/iframe-entry.ts +1 -0
  96. package/src/canvas/iframe-host.ts +4 -0
  97. package/src/canvas/iframe-patch.ts +47 -21
  98. package/src/canvas/iframe-protocol.ts +9 -0
  99. package/src/canvas/iframe-render.ts +50 -16
  100. package/src/commands/app-commands.ts +4 -0
  101. package/src/commands/command-args.ts +29 -0
  102. package/src/commands/context.ts +15 -1
  103. package/src/commands/defaults.ts +29 -1
  104. package/src/commands/levels.ts +16 -0
  105. package/src/commands/live-context.ts +3 -0
  106. package/src/content/collection-match.ts +267 -0
  107. package/src/content/entry-commands.ts +38 -29
  108. package/src/content/entry-fields.ts +6 -0
  109. package/src/editor/file-drop-action.ts +2 -1
  110. package/src/editor/shortcuts.ts +5 -0
  111. package/src/files/file-ops.ts +10 -42
  112. package/src/files/files.ts +487 -61
  113. package/src/files/fs-events.ts +9 -0
  114. package/src/files/gitignore.ts +432 -0
  115. package/src/files/media-paths.ts +37 -14
  116. package/src/files/media-upload.ts +47 -6
  117. package/src/files/serialize-document.ts +60 -0
  118. package/src/format/convert-file.ts +511 -0
  119. package/src/format/format-choices.ts +199 -0
  120. package/src/grid/grid-idle.ts +45 -0
  121. package/src/grid/grid-view.ts +35 -0
  122. package/src/grid/schema-columns.ts +2 -1
  123. package/src/grid/sources/content-source.ts +24 -3
  124. package/src/media/media-open.ts +58 -0
  125. package/src/media/media-pane.ts +310 -0
  126. package/src/new-project/import-tab.ts +333 -160
  127. package/src/new-project/new-project-modal.ts +27 -34
  128. package/src/packages/ensure-deps.ts +14 -7
  129. package/src/packages/jxsuite-update.ts +11 -11
  130. package/src/page-params.ts +10 -46
  131. package/src/panels/activity-bar.ts +45 -16
  132. package/src/panels/ai-chat/attached-context.ts +6 -1
  133. package/src/panels/ai-chat/chat-view.ts +255 -13
  134. package/src/panels/ai-chat/composer.ts +21 -80
  135. package/src/panels/ai-panel.ts +116 -2
  136. package/src/panels/frontmatter-fields.ts +6 -2
  137. package/src/panels/navigator-panels.ts +7 -6
  138. package/src/panels/properties-panel.ts +8 -2
  139. package/src/panels/seo-modal.ts +5 -6
  140. package/src/panels/settings-menu.ts +799 -0
  141. package/src/panels/signals-panel.ts +2 -1
  142. package/src/panels/toolbar.ts +135 -15
  143. package/src/platforms/cloud.ts +34 -3
  144. package/src/platforms/devserver.ts +72 -34
  145. package/src/preview/preview-overlay.ts +226 -0
  146. package/src/services/ai-ask.ts +247 -0
  147. package/src/services/ai-import-tools.ts +494 -0
  148. package/src/services/ai-models.ts +101 -11
  149. package/src/services/ai-project-tools.ts +20 -26
  150. package/src/services/ai-settings.ts +69 -71
  151. package/src/services/ai-system-prompt.ts +88 -2
  152. package/src/services/ai-turn-signal.ts +70 -0
  153. package/src/services/cf-settings.ts +19 -37
  154. package/src/services/connection.ts +74 -0
  155. package/src/services/context-manager.ts +89 -0
  156. package/src/services/document-assistant.ts +49 -7
  157. package/src/services/idle.ts +6 -1
  158. package/src/services/import-client.ts +33 -6
  159. package/src/services/import-run.ts +158 -0
  160. package/src/services/import-seed.ts +120 -0
  161. package/src/services/jx-validate.ts +58 -6
  162. package/src/services/project-adoption.ts +71 -0
  163. package/src/services/references.ts +0 -0
  164. package/src/services/settings/definitions.ts +181 -0
  165. package/src/services/settings/kernel.ts +335 -0
  166. package/src/services/settings/write-queue.ts +116 -0
  167. package/src/services/tool-executor.ts +34 -2
  168. package/src/settings/contexts-section.ts +45 -3
  169. package/src/settings/dependencies-editor.ts +43 -23
  170. package/src/settings/general-settings.ts +30 -12
  171. package/src/settings/preferences-accounts.ts +6 -19
  172. package/src/settings/preferences-dialog.ts +18 -41
  173. package/src/settings/preferences-keymap.ts +8 -18
  174. package/src/settings/preferences-sections.ts +57 -0
  175. package/src/settings/schema-field-ui.ts +2 -2
  176. package/src/settings/settings-document.ts +65 -9
  177. package/src/shell.ts +6 -14
  178. package/src/studio.ts +65 -7
  179. package/src/tabs/transact.ts +42 -19
  180. package/src/types.ts +164 -8
  181. package/src/ui/ai-credentials-form.ts +52 -27
  182. package/src/ui/ai-model-picker.ts +162 -0
  183. package/src/ui/choice-field.ts +72 -0
  184. package/src/ui/layers.ts +83 -5
  185. package/src/ui/media-picker.ts +6 -11
  186. package/src/utils/studio-utils.ts +43 -31
  187. package/styles/forced-colors.css +7 -0
  188. package/styles/overlays.css +256 -0
  189. package/styles/panels.css +13 -1
  190. package/styles/shell.css +111 -0
  191. package/dist/chunks/Overlay.dev-d2ajy6sj.js +0 -23
  192. package/dist/chunks/cf-settings-g5fbf2zp.js +0 -17
  193. package/dist/chunks/content-source-k9724vcv.js +0 -39
  194. package/dist/chunks/files-yew27sn9.js +0 -69
  195. package/dist/chunks/layers-panel-qnsghwwd.js +0 -59
  196. package/dist/chunks/publish-panel-a0pdft5w.js +0 -21
  197. package/dist/chunks/quick-search-9avyc4pc.js +0 -54
  198. package/dist/chunks/right-panel-kcnhtc5j.js +0 -38
  199. package/dist/chunks/sp-overlay.dev-s18hymn9.js +0 -18
  200. package/dist/chunks/sp-popover.dev-dj9x7e7a.js +0 -9
  201. package/dist/chunks/sp-progress-circle.dev-0zxcyz3r.js +0 -15
  202. package/dist/chunks/sp-tooltip.dev-5c6d1kjz.js +0 -15
  203. package/dist/chunks/studio-a7pzveq1.js +0 -110
  204. package/dist/chunks/studio-c31yb4t6.js +0 -55
  205. package/dist/chunks/studio-ra7ar50f.js +0 -6682
  206. package/src/canvas/content-assets.ts +0 -263
  207. package/src/canvas/site-style-css.ts +0 -121
  208. package/src/services/settings-store.ts +0 -99
@@ -4,8 +4,8 @@
4
4
  * These are all side-effect-free functions used by style/properties/events panels.
5
5
  */
6
6
 
7
- import { defaultContentFormat, formatByName } from "../format/format-host";
8
- import type { ContentSectionEntry } from "../types";
7
+ import { collectionForFile } from "../content/collection-match";
8
+ import { defaultContentFormat } from "../format/format-host";
9
9
  import type { ProjectConfig } from "@jxsuite/schema/types";
10
10
 
11
11
  /**
@@ -117,6 +117,26 @@ export function abbreviateValue(val: string) {
117
117
  return map[val] || val;
118
118
  }
119
119
 
120
+ /**
121
+ * True when a schema `format` names a MEDIA reference.
122
+ *
123
+ * Two spellings, and both are real. `"uri-reference"` is JSON Schema's own and the one the spec
124
+ * uses — it is what the content loader keys its asset rewrite on (`rewriteEntryAssets`) and what a
125
+ * schema written against the documentation says. `"image"` is Studio's own shorthand, used by
126
+ * component props and settings schemas.
127
+ *
128
+ * They were accepted in different places, so which editor a field got depended on which panel was
129
+ * asking: `inferInputType` took both, the frontmatter panel took only `"image"`, and the drop
130
+ * target, the signals panel and the data grid each took only one. One predicate, so a field is a
131
+ * media field everywhere or nowhere.
132
+ *
133
+ * @param {unknown} format - A schema entry's `format`
134
+ * @returns {boolean}
135
+ */
136
+ export function isMediaFormat(format: unknown): boolean {
137
+ return format === "image" || format === "uri-reference";
138
+ }
139
+
120
140
  /**
121
141
  * Determine input widget type from a css-meta entry
122
142
  *
@@ -136,7 +156,7 @@ export function inferInputType(entry: Record<string, unknown>) {
136
156
  if (entry.format === "color") {
137
157
  return "color";
138
158
  }
139
- if (entry.format === "uri-reference") {
159
+ if (isMediaFormat(entry.format)) {
140
160
  return "media";
141
161
  }
142
162
  if (entry.$units !== undefined) {
@@ -155,8 +175,14 @@ export function inferInputType(entry: Record<string, unknown>) {
155
175
  }
156
176
 
157
177
  /**
158
- * Match a document path to a content type and return its schema. Compares the content type's
159
- * `source` directory against the document path prefix, using `format` for extension matching.
178
+ * Match a document path to a content type and return its schema.
179
+ *
180
+ * Delegates to `content/collection-match.ts`, which is the ONE matcher — the reason it takes a
181
+ * config rather than reading `projectState`. Two rules are added here and belong here, because they
182
+ * are about the FORM rather than about membership: a collection that declares no `schema` has no
183
+ * fields to draw, and a file whose extension is not the collection's is not one of its entries.
184
+ * Membership itself — the `{locale}` expansion, the recursive subdirectory, the single-file
185
+ * catalogue, longest-source-wins — is the matcher's, and is no longer restated here.
160
186
  *
161
187
  * @param {string | null} documentPath — project-relative path (e.g. "content/products/widget.md")
162
188
  * @param {ProjectConfig | null | undefined} projectConfig — parsed project.json
@@ -169,34 +195,20 @@ export function findContentTypeSchema(
169
195
  if (!documentPath || !projectConfig?.content) {
170
196
  return null;
171
197
  }
172
- // Content-type `source` prefixes are always forward-slash. The desktop platform can hand us
173
- // OS-native backslash paths on Windows, so normalize before prefix matching.
174
- const docPath = documentPath.replaceAll("\\", "/");
175
- for (const [name, def] of Object.entries(
176
- projectConfig.content as Record<string, ContentSectionEntry>,
177
- )) {
178
- if (!def.source || !def.schema) {
179
- continue;
180
- }
181
- const src = def.source.replace(/^\.\//, "").replace(/\/$/, "");
182
- const hasExt = src.includes(".") && !src.endsWith("/");
183
- if (hasExt) {
184
- if (docPath === src || docPath.endsWith(`/${src}`)) {
185
- return { name, schema: def.schema };
186
- }
187
- } else {
188
- const ext =
189
- def.format === "json"
190
- ? ".json"
191
- : (formatByName(def.format)?.extensions[0] ??
192
- defaultContentFormat()?.extensions[0] ??
193
- ".json");
194
- if (docPath.startsWith(`${src}/`) && docPath.endsWith(ext)) {
195
- return { name, schema: def.schema };
196
- }
198
+ const match = collectionForFile(documentPath, projectConfig);
199
+ if (!match || !match.def.schema) {
200
+ return null;
201
+ }
202
+ /* A single-file source is matched AS that file, so its extension is settled by construction.
203
+ A directory-backed one is not: a `.json` sitting beside `.md` posts is somebody else's file,
204
+ and drawing the collection's fields over it would invite edits nothing will ever read. */
205
+ if (!match.fileBacked) {
206
+ const ext = match.ext ?? defaultContentFormat()?.extensions[0] ?? ".json";
207
+ if (!documentPath.toLowerCase().endsWith(ext.toLowerCase())) {
208
+ return null;
197
209
  }
198
210
  }
199
- return null;
211
+ return { name: match.name, schema: match.def.schema };
200
212
  }
201
213
 
202
214
  /**
@@ -48,6 +48,13 @@
48
48
  outline-offset: -2px;
49
49
  }
50
50
 
51
+ /* The rail's gear while its menu is open. That state is drawn with a `background`, which this
52
+ mode re-forces to the system canvas — so it says nothing. An outline says it instead. */
53
+ .rail-item--menu-open {
54
+ outline: 2px solid Highlight;
55
+ outline-offset: -2px;
56
+ }
57
+
51
58
  /* The drop target. A 3px translucent ring is invisible here twice over — shadow and alpha. */
52
59
  .drop-target,
53
60
  .is-drop-target {
@@ -768,6 +768,14 @@
768
768
  font-size: var(--spectrum-font-size-75, 12px);
769
769
  color: var(--danger);
770
770
  }
771
+ /* A problem the file already had, said once at section level. Deliberately not `-error`: it did not
772
+ refuse anything and it belongs to no control, so it is a warning about the file rather than a
773
+ rejection of an edit — §16.1's distinction, in the one place a settings section can make it. */
774
+ .settings-section-notice {
775
+ margin: 6px 0 0;
776
+ font-size: var(--spectrum-font-size-75, 12px);
777
+ color: var(--warning);
778
+ }
771
779
  .settings-site-name,
772
780
  .settings-site-url {
773
781
  width: 100%;
@@ -860,6 +868,13 @@
860
868
  font-weight: 500;
861
869
  color: var(--fg-dim);
862
870
  }
871
+ /* Explanatory text under a field's control — what the number means, not what the field is
872
+ called. Sits below rather than beside so a long sentence wraps instead of squeezing the input. */
873
+ .new-project-hint {
874
+ font-size: var(--spectrum-font-size-75, 12px);
875
+ color: var(--fg-dim);
876
+ line-height: 1.4;
877
+ }
863
878
  .new-project-error {
864
879
  font-size: var(--spectrum-font-size-75, 12px);
865
880
  color: var(--danger);
@@ -1014,6 +1029,35 @@
1014
1029
  grid-template-columns: 1fr 1fr;
1015
1030
  gap: 12px;
1016
1031
  }
1032
+ /* Breakpoints: a mode picker, whichever value control that mode takes, and the rounding rule. It
1033
+ wraps rather than scrolls — the widths field is the one that needs room, and it should get it. */
1034
+ .new-project-import-breakpoints {
1035
+ display: flex;
1036
+ flex-wrap: wrap;
1037
+ align-items: center;
1038
+ gap: 8px;
1039
+ }
1040
+ .new-project-breakpoint-mode {
1041
+ min-width: 132px;
1042
+ }
1043
+ .new-project-breakpoint-rounding {
1044
+ min-width: 132px;
1045
+ }
1046
+ .new-project-breakpoint-count,
1047
+ .new-project-min-fidelity {
1048
+ width: 96px;
1049
+ }
1050
+ .new-project-breakpoint-widths {
1051
+ flex: 1;
1052
+ min-width: 160px;
1053
+ }
1054
+ /* One line under a control saying what it will do. Not an error and not a label — the sentence a
1055
+ reader needs to predict the outcome before the run rather than after it. */
1056
+ .new-project-hint {
1057
+ font-size: var(--spectrum-font-size-75, 12px);
1058
+ color: var(--fg-dim);
1059
+ line-height: 1.5;
1060
+ }
1017
1061
  .new-project-import-progress {
1018
1062
  display: flex;
1019
1063
  align-items: center;
@@ -1044,6 +1088,13 @@
1044
1088
  .new-project-agent-prompt {
1045
1089
  min-height: 120px;
1046
1090
  }
1091
+ .new-project-import-prompt {
1092
+ width: 100%;
1093
+ min-height: 90px;
1094
+ }
1095
+ .new-project-import-model {
1096
+ width: 100%;
1097
+ }
1047
1098
  .new-project-step-context {
1048
1099
  font-size: var(--spectrum-font-size-75, 12px);
1049
1100
  color: var(--fg-dim);
@@ -2592,6 +2643,28 @@
2592
2643
  line-height: 1.5;
2593
2644
  }
2594
2645
 
2646
+ /* One labelled choice inside a dialog body (`ui/choice-field.ts`) — the New File format picker and
2647
+ the Convert target picker. Stacked rather than inline: the label reads as a question about the
2648
+ field beneath it, and a picker beside a full-width text field wins a width fight neither should
2649
+ be having. */
2650
+ .choice-row {
2651
+ display: flex;
2652
+ flex-direction: column;
2653
+ gap: 4px;
2654
+ margin: 0 0 12px;
2655
+ }
2656
+ .choice-row sp-picker {
2657
+ width: 100%;
2658
+ }
2659
+ /* What a one-row choice degrades to. Sized like the picker it replaces so the dialog does not
2660
+ change height when the project gains a second format. */
2661
+ .choice-static {
2662
+ padding: 4px 0;
2663
+ color: var(--fg-dim);
2664
+ font-size: var(--spectrum-font-size-100, 14px);
2665
+ line-height: 1.5;
2666
+ }
2667
+
2595
2668
  /* A panel withholding a render because one of its own fields has focus (`panel-scheduler.ts`).
2596
2669
  The panel is deliberately stale — finishing your sentence beats being current — but it used to
2597
2670
  make that trade in silence, which is indistinguishable from a panel that has stopped working.
@@ -2737,3 +2810,186 @@
2737
2810
  .jx-layer--toast {
2738
2811
  z-index: 4000;
2739
2812
  }
2813
+
2814
+ /* The gear menu's section submenu.
2815
+
2816
+ Project Settings has ~16 sections once the extensions have contributed theirs, which is taller
2817
+ than a short window. The menu's own placement floors `top` at 4px so the first rows can never be
2818
+ pushed off the top edge; this is the other half — the list scrolls inside itself rather than
2819
+ demanding a viewport it cannot have. */
2820
+ /* The gear menu's rows.
2821
+
2822
+ A min-width so the widest title and its chord are not crushed into each other: the rows are
2823
+ `Preferences… ⌘,` and `Open Project Settings ⌘⇧,`, and Spectrum sizes a menu to its content. */
2824
+ .settings-menu {
2825
+ min-width: 260px;
2826
+ }
2827
+
2828
+ /* One flex cell for the trailing chord and chevron.
2829
+
2830
+ They must be a SINGLE slotted node. Spectrum's menu-item grid gives `[slot=value]` one cell with
2831
+ `justify-self: end`, applied per assigned node — so a chord and a chevron slotted separately are
2832
+ both pinned to the same right edge, on top of each other. */
2833
+ .settings-menu-value {
2834
+ display: inline-flex;
2835
+ align-items: center;
2836
+ gap: 8px;
2837
+ padding-left: 24px;
2838
+ color: var(--fg-dim);
2839
+ }
2840
+
2841
+ .settings-submenu {
2842
+ max-height: min(60vh, 480px);
2843
+ overflow-y: auto;
2844
+ overscroll-behavior: contain;
2845
+ }
2846
+
2847
+ /* ─── Media viewer ────────────────────────────────────────────────────────────
2848
+ A pane that SHOWS a file rather than editing one (`media/media-pane.ts`). The stage takes the
2849
+ room and the details column stays a fixed width, so the asset is the thing you are looking at
2850
+ and the facts about it are beside it rather than on top of it. It scrolls itself — a wheel over
2851
+ an image is a scroll, not a zoom, which is why `media` is in shortcuts.ts's self-scrolling set. */
2852
+ .media-viewer {
2853
+ height: 100%;
2854
+ display: flex;
2855
+ gap: 16px;
2856
+ padding: 16px;
2857
+ overflow-y: auto;
2858
+ background: var(--bg-panel);
2859
+ }
2860
+ .media-stage {
2861
+ flex: 1;
2862
+ min-width: 0;
2863
+ display: flex;
2864
+ align-items: flex-start;
2865
+ justify-content: center;
2866
+ }
2867
+ /* Never larger than its own pixels: an upscaled thumbnail is a lie about the asset, and judging
2868
+ whether an imported image is big enough is the whole reason somebody opens this. */
2869
+ .media-image {
2870
+ max-width: 100%;
2871
+ height: auto;
2872
+ border: 1px solid var(--border);
2873
+ border-radius: var(--radius);
2874
+ background: var(--bg-input);
2875
+ }
2876
+ .media-video,
2877
+ .media-embed {
2878
+ width: 100%;
2879
+ max-height: 70vh;
2880
+ border: 1px solid var(--border);
2881
+ border-radius: var(--radius);
2882
+ background: var(--bg-input);
2883
+ }
2884
+ .media-audio {
2885
+ width: 100%;
2886
+ }
2887
+ .media-specimen {
2888
+ width: 100%;
2889
+ padding: 16px;
2890
+ border: 1px solid var(--border);
2891
+ border-radius: var(--radius);
2892
+ background: var(--bg-input);
2893
+ color: var(--fg);
2894
+ }
2895
+ .media-specimen-line {
2896
+ margin: 0 0 12px;
2897
+ line-height: 1.3;
2898
+ overflow-wrap: anywhere;
2899
+ }
2900
+ .media-unviewable {
2901
+ padding: 24px;
2902
+ border: 1px dashed var(--border);
2903
+ border-radius: var(--radius);
2904
+ color: var(--fg-dim);
2905
+ text-align: center;
2906
+ }
2907
+ .media-note {
2908
+ font-size: var(--spectrum-font-size-75, 12px);
2909
+ color: var(--fg-dim);
2910
+ }
2911
+ .media-details {
2912
+ flex: 0 0 260px;
2913
+ display: flex;
2914
+ flex-direction: column;
2915
+ gap: 12px;
2916
+ }
2917
+ .media-name {
2918
+ margin: 0;
2919
+ font-size: var(--spectrum-font-size-100, 14px);
2920
+ color: var(--fg);
2921
+ overflow-wrap: anywhere;
2922
+ }
2923
+ .media-facts {
2924
+ margin: 0;
2925
+ font-size: var(--spectrum-font-size-75, 12px);
2926
+ color: var(--fg-dim);
2927
+ }
2928
+ /* The reference a document writes for this file — `/hero.jpg` for `public/hero.jpg`, which shares
2929
+ not one segment with it. Getting this wrong is the commonest way an image goes missing. */
2930
+ .media-ref {
2931
+ display: flex;
2932
+ align-items: center;
2933
+ gap: 6px;
2934
+ }
2935
+ .media-ref-value {
2936
+ flex: 1;
2937
+ min-width: 0;
2938
+ font-family: var(--font-mono);
2939
+ font-size: 11px;
2940
+ background: var(--bg-input);
2941
+ border: 1px solid var(--border);
2942
+ border-radius: var(--radius);
2943
+ padding: 3px 6px;
2944
+ overflow-wrap: anywhere;
2945
+ }
2946
+ .media-usage {
2947
+ display: flex;
2948
+ flex-direction: column;
2949
+ }
2950
+ .media-usage-title {
2951
+ margin: 0 0 4px;
2952
+ font-size: var(--spectrum-font-size-75, 12px);
2953
+ font-weight: 500;
2954
+ color: var(--fg-dim);
2955
+ }
2956
+ .media-usage-headline {
2957
+ margin: 0;
2958
+ font-size: var(--spectrum-font-size-75, 12px);
2959
+ color: var(--fg-dim);
2960
+ }
2961
+ .media-usage-list {
2962
+ list-style: none;
2963
+ margin: 8px 0 0;
2964
+ padding: 0;
2965
+ display: flex;
2966
+ flex-direction: column;
2967
+ gap: 2px;
2968
+ }
2969
+ .media-usage-list li {
2970
+ display: flex;
2971
+ align-items: baseline;
2972
+ gap: 6px;
2973
+ font-size: var(--spectrum-font-size-75, 12px);
2974
+ }
2975
+ .media-usage-link {
2976
+ flex: 1;
2977
+ min-width: 0;
2978
+ background: none;
2979
+ border: none;
2980
+ padding: 0;
2981
+ text-align: left;
2982
+ color: var(--accent);
2983
+ cursor: pointer;
2984
+ font: inherit;
2985
+ overflow-wrap: anywhere;
2986
+ }
2987
+ .media-usage-link:hover {
2988
+ text-decoration: underline;
2989
+ }
2990
+ .media-usage-count {
2991
+ flex: 0 0 auto;
2992
+ font-family: var(--font-mono);
2993
+ font-size: 10px;
2994
+ color: var(--fg-dim);
2995
+ }
package/styles/panels.css CHANGED
@@ -60,6 +60,16 @@
60
60
  color: var(--fg);
61
61
  border-left-color: var(--accent);
62
62
  }
63
+ /* The gear while its menu is open.
64
+
65
+ Deliberately NOT `.selected`: that class means "this is the panel you are looking at" and paints
66
+ the accent left-border, so reusing it would draw the gear as a seventh selected panel. What this
67
+ says is narrower — the menu you opened is still up. */
68
+ .rail-item--menu-open {
69
+ opacity: 1;
70
+ color: var(--fg);
71
+ background: var(--hover-bg);
72
+ }
63
73
  .rail-item:focus-visible {
64
74
  outline: 2px solid var(--accent);
65
75
  outline-offset: -2px;
@@ -469,7 +479,9 @@
469
479
  font-size: 0;
470
480
  overflow: hidden;
471
481
  }
472
- .empty-text-placeholder:not([contenteditable])::after {
482
+ .empty-text-placeholder:is(:empty, :has(> br:only-child)):not([data-jx-active-block]):not(
483
+ [contenteditable]
484
+ )::after {
473
485
  content: "Click here to add text...";
474
486
  color: color-mix(in srgb, var(--fg-dim, #808080) 40%, transparent);
475
487
  font-style: italic;
package/styles/shell.css CHANGED
@@ -596,6 +596,117 @@
596
596
  color: var(--fg-dim);
597
597
  font-family: var(--font-mono);
598
598
  }
599
+ /* A question the assistant is waiting on. Deliberately louder than a tool chip and quieter than
600
+ an error: it is the one thing in the transcript that will not proceed without the reader. */
601
+ .ai-ask {
602
+ display: flex;
603
+ flex-direction: column;
604
+ gap: 6px;
605
+ align-self: stretch;
606
+ background: var(--hover-bg);
607
+ border-left: 2px solid var(--accent);
608
+ border-radius: var(--radius);
609
+ padding: 8px 10px;
610
+ }
611
+ .ai-ask[data-outcome="ok"],
612
+ .ai-ask[data-outcome="unanswered"],
613
+ .ai-ask[data-outcome="failed"] {
614
+ border-left-color: var(--border);
615
+ }
616
+ .ai-ask-question {
617
+ font-size: var(--spectrum-font-size-75, 12px);
618
+ color: var(--fg);
619
+ line-height: 1.5;
620
+ }
621
+ .ai-ask-context {
622
+ font-size: var(--spectrum-font-size-50, 11px);
623
+ color: var(--fg-dim);
624
+ line-height: 1.5;
625
+ }
626
+ .ai-ask-options {
627
+ display: flex;
628
+ flex-wrap: wrap;
629
+ align-items: center;
630
+ gap: 6px;
631
+ }
632
+ .ai-ask-skip {
633
+ margin-inline-start: auto;
634
+ }
635
+ .ai-ask-answer {
636
+ align-self: flex-start;
637
+ max-width: 100%;
638
+ background: var(--accent);
639
+ color: var(--accent-fg);
640
+ border-radius: var(--radius);
641
+ padding: 3px 8px;
642
+ font-size: var(--spectrum-font-size-50, 11px);
643
+ overflow-wrap: anywhere;
644
+ }
645
+ .ai-ask-outcome {
646
+ font-size: var(--spectrum-font-size-50, 11px);
647
+ color: var(--fg-dim);
648
+ line-height: 1.5;
649
+ }
650
+ /* An import, under the chip that started it. It reports for minutes and then stays: the summary
651
+ line is the run's outcome once it has one, and the log below is a scroller the reader owns —
652
+ it follows the newest line until they scroll away from it, and stops following while they read.
653
+ It was a fixed six-line tail that ellipsed every message and vanished the moment the run
654
+ finished, which is to say the account of a successful import was destroyed by its success. */
655
+ .ai-import-progress {
656
+ align-self: stretch;
657
+ background: var(--bg-input);
658
+ border: 1px solid var(--border);
659
+ border-radius: var(--radius);
660
+ padding: 6px 8px;
661
+ }
662
+ .ai-import-head {
663
+ display: flex;
664
+ align-items: center;
665
+ gap: 6px;
666
+ font-size: var(--spectrum-font-size-50, 11px);
667
+ color: var(--fg);
668
+ cursor: pointer;
669
+ list-style: none;
670
+ }
671
+ .ai-import-head::-webkit-details-marker {
672
+ display: none;
673
+ }
674
+ .ai-import-message {
675
+ flex: 1;
676
+ min-width: 0;
677
+ overflow: hidden;
678
+ text-overflow: ellipsis;
679
+ white-space: nowrap;
680
+ }
681
+ /* How many lines are folded away, so a collapsed run still says how much it has to show. */
682
+ .ai-import-count {
683
+ flex: 0 0 auto;
684
+ font-family: var(--font-mono);
685
+ font-size: 10px;
686
+ color: var(--fg-dim);
687
+ }
688
+ .ai-import-phase {
689
+ color: var(--fg-dim);
690
+ font-family: var(--font-mono);
691
+ flex: 0 0 auto;
692
+ margin-right: 4px;
693
+ }
694
+ .ai-import-log {
695
+ margin-top: 4px;
696
+ max-height: 40vh;
697
+ overflow-y: auto;
698
+ overscroll-behavior: contain;
699
+ font-family: var(--font-mono);
700
+ font-size: 10px;
701
+ line-height: 1.6;
702
+ color: var(--fg-dim);
703
+ }
704
+ /* Wraps rather than ellipses: a phase line names a page, a count or a file, and the end of it is
705
+ usually the part worth reading. */
706
+ .ai-import-log-line {
707
+ overflow-wrap: anywhere;
708
+ white-space: pre-wrap;
709
+ }
599
710
  .ai-msg-tool-error {
600
711
  background: var(--hover-bg);
601
712
  border-left: 2px solid var(--danger);
@@ -1,23 +0,0 @@
1
- import {
2
- LONGPRESS_INSTRUCTIONS,
3
- Overlay
4
- } from "./studio-tzx3xmvx.js";
5
- import"./studio-ahnzd9rg.js";
6
- import"./studio-ay8wcr2b.js";
7
- import"./studio-z6nw2ek2.js";
8
- import"./studio-8q517dfr.js";
9
- import"./studio-xm3dbxvn.js";
10
- import"./studio-0rqqhrdy.js";
11
- import"./studio-c31yb4t6.js";
12
- import"./studio-2w11grav.js";
13
- import"./studio-twsafr1e.js";
14
- import"./studio-kvfx9z2c.js";
15
- import"./studio-5x5774ak.js";
16
- import"./studio-a0tswy0w.js";
17
- export {
18
- LONGPRESS_INSTRUCTIONS,
19
- Overlay
20
- };
21
-
22
- //# debugId=A65C67C23042201664756E2164756E21
23
- //# sourceMappingURL=Overlay.dev-d2ajy6sj.js.map
@@ -1,17 +0,0 @@
1
- import {
2
- getCfAccountId,
3
- getCfToken,
4
- setCfAccountId,
5
- setCfToken
6
- } from "./studio-a7pzveq1.js";
7
- import"./studio-sas7mt3k.js";
8
- import"./studio-a0tswy0w.js";
9
- export {
10
- getCfAccountId,
11
- getCfToken,
12
- setCfAccountId,
13
- setCfToken
14
- };
15
-
16
- //# debugId=B652056CE853690D64756E2164756E21
17
- //# sourceMappingURL=cf-settings-g5fbf2zp.js.map
@@ -1,39 +0,0 @@
1
- import {
2
- PATH_FIELD,
3
- collectionDirs,
4
- collectionInfo,
5
- createCollectionSource,
6
- createPagesSource,
7
- listCollectionEntryIds,
8
- reloadDraftAwareGrids
9
- } from "./studio-26sv44br.js";
10
- import"./studio-2w11grav.js";
11
- import"./studio-bw5dz6km.js";
12
- import"./studio-cz2j1c0g.js";
13
- import"./studio-28xc8ws4.js";
14
- import"./studio-aweyr4v1.js";
15
- import"./studio-pyrw8h0w.js";
16
- import"./studio-ra7ar50f.js";
17
- import"./studio-twsafr1e.js";
18
- import"./studio-kvfx9z2c.js";
19
- import"./studio-5x5774ak.js";
20
- import"./studio-g1wdche0.js";
21
- import"./studio-s519zc99.js";
22
- import"./studio-cjm7fdjf.js";
23
- import"./studio-rqemfhz6.js";
24
- import"./studio-sas7mt3k.js";
25
- import"./studio-5ehhackm.js";
26
- import"./studio-53n8bp04.js";
27
- import"./studio-a0tswy0w.js";
28
- export {
29
- PATH_FIELD,
30
- collectionDirs,
31
- collectionInfo,
32
- createCollectionSource,
33
- createPagesSource,
34
- listCollectionEntryIds,
35
- reloadDraftAwareGrids
36
- };
37
-
38
- //# debugId=CB1FE05CE1005B6D64756E2164756E21
39
- //# sourceMappingURL=content-source-k9724vcv.js.map