@jxsuite/studio 2.0.0 → 2.1.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 (419) hide show
  1. package/canvas.html +21 -0
  2. package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
  3. package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
  4. package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
  5. package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
  6. package/dist/chunks/{components-0hzentwq.js → components-2bpqp4mq.js} +5 -7
  7. package/dist/chunks/{components-0hzentwq.js.map → components-2bpqp4mq.js.map} +1 -1
  8. package/dist/chunks/content-source-34gnkbnn.js +38 -0
  9. package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
  10. package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
  11. package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
  12. package/dist/chunks/extension-sections-6mqydz35.js +301 -0
  13. package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
  14. package/dist/chunks/files-8kn321h1.js +70 -0
  15. package/dist/chunks/files-8kn321h1.js.map +9 -0
  16. package/dist/chunks/{format-host-2c188n41.js → format-host-mkwsmt8d.js} +3 -3
  17. package/dist/chunks/git-panel-tjbr191d.js +51 -0
  18. package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
  19. package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
  20. package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
  21. package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
  22. package/dist/chunks/layers-panel-87pb25km.js +58 -0
  23. package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
  24. package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
  25. package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
  26. package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
  27. package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
  28. package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
  29. package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
  30. package/dist/chunks/right-panel-zpdxd98t.js +37 -0
  31. package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
  32. package/dist/chunks/section-registry-zmckaxf4.js +30 -0
  33. package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
  34. package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
  35. package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
  36. package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
  37. package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
  38. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
  39. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
  40. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
  41. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
  42. package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
  43. package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
  44. package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
  45. package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
  46. package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
  47. package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
  48. package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
  49. package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
  50. package/dist/chunks/studio-41exgzhq.js +6690 -0
  51. package/dist/chunks/studio-41exgzhq.js.map +38 -0
  52. package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
  53. package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
  54. package/dist/chunks/studio-50k77cca.js +1787 -0
  55. package/dist/chunks/studio-50k77cca.js.map +18 -0
  56. package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
  57. package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
  58. package/dist/chunks/studio-6f0am8f2.js +53 -0
  59. package/dist/chunks/studio-6f0am8f2.js.map +10 -0
  60. package/dist/chunks/studio-6nmjc5qk.js +7002 -0
  61. package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
  62. package/dist/chunks/studio-7afd21nw.js +67 -0
  63. package/dist/chunks/studio-7afd21nw.js.map +10 -0
  64. package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
  65. package/dist/chunks/studio-7bmdvzne.js.map +10 -0
  66. package/dist/chunks/studio-8jpzqk5s.js +128 -0
  67. package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
  68. package/dist/chunks/studio-94m77tgk.js +1482 -0
  69. package/dist/chunks/studio-94m77tgk.js.map +13 -0
  70. package/dist/chunks/studio-9je6w5sq.js +1000 -0
  71. package/dist/chunks/studio-9je6w5sq.js.map +16 -0
  72. package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
  73. package/dist/chunks/{studio-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
  74. package/dist/chunks/{studio-97qcgvdn.js.map → studio-adn0z1k3.js.map} +3 -3
  75. package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
  76. package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
  77. package/dist/chunks/studio-bw5dz6km.js +608 -0
  78. package/dist/chunks/studio-bw5dz6km.js.map +21 -0
  79. package/dist/chunks/studio-c6s5getc.js +4232 -0
  80. package/dist/chunks/studio-c6s5getc.js.map +39 -0
  81. package/dist/chunks/studio-cjm7fdjf.js +451 -0
  82. package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
  83. package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
  84. package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
  85. package/dist/chunks/studio-dg7zyt5x.js +28 -0
  86. package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
  87. package/dist/chunks/studio-dzcyvvvz.js +166 -0
  88. package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
  89. package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
  90. package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
  91. package/dist/chunks/studio-f12h6177.js +411 -0
  92. package/dist/chunks/studio-f12h6177.js.map +13 -0
  93. package/dist/chunks/studio-hbp1s8m9.js +1817 -0
  94. package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
  95. package/dist/chunks/studio-k2sxjph5.js +15295 -0
  96. package/dist/chunks/studio-k2sxjph5.js.map +235 -0
  97. package/dist/chunks/studio-myje51t3.js +385 -0
  98. package/dist/chunks/studio-myje51t3.js.map +12 -0
  99. package/dist/chunks/studio-na6rwzhw.js +353 -0
  100. package/dist/chunks/studio-na6rwzhw.js.map +11 -0
  101. package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
  102. package/dist/chunks/studio-p471gg5n.js.map +14 -0
  103. package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
  104. package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
  105. package/dist/chunks/{studio-hhj92gcr.js → studio-s519zc99.js} +3 -3
  106. package/dist/chunks/studio-sas7mt3k.js +75 -0
  107. package/dist/chunks/studio-sas7mt3k.js.map +10 -0
  108. package/dist/chunks/studio-t5wqwzdh.js +74 -0
  109. package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
  110. package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
  111. package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
  112. package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
  113. package/dist/chunks/studio-tr20m8g8.js.map +9 -0
  114. package/dist/chunks/{studio-ygzav7z5.js → studio-v96qfnww.js} +5514 -4291
  115. package/dist/chunks/studio-v96qfnww.js.map +54 -0
  116. package/dist/chunks/studio-vcetc91k.js +659 -0
  117. package/dist/chunks/studio-vcetc91k.js.map +10 -0
  118. package/dist/chunks/{studio-n9zmpxjg.js → studio-vmymjefp.js} +2972 -4937
  119. package/dist/chunks/studio-vmymjefp.js.map +98 -0
  120. package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
  121. package/dist/chunks/studio-x9hmy5kr.js +390 -0
  122. package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
  123. package/dist/chunks/studio-xa0ce0n7.js +335 -0
  124. package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
  125. package/dist/chunks/studio-xm3dbxvn.js +378 -0
  126. package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
  127. package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
  128. package/dist/chunks/studio-zv37yrfa.js +1054 -0
  129. package/dist/chunks/studio-zv37yrfa.js.map +13 -0
  130. package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
  131. package/dist/chunks/ws-client-654ts66j.js.map +11 -0
  132. package/dist/iframe-entry.js +668 -230
  133. package/dist/studio.js +23711 -35185
  134. package/index.html +35 -4685
  135. package/package.json +17 -15
  136. package/src/about/about-modal.ts +42 -11
  137. package/src/browse/library-commands.ts +240 -0
  138. package/src/browse/library-layouts.ts +369 -0
  139. package/src/browse/library-model.ts +396 -0
  140. package/src/browse/library-pane.ts +1049 -0
  141. package/src/browse/library-preview.ts +252 -0
  142. package/src/browse/library-source.ts +150 -0
  143. package/src/canvas/canvas-helpers.ts +33 -9
  144. package/src/canvas/canvas-live-render.ts +45 -29
  145. package/src/canvas/canvas-patcher.ts +151 -31
  146. package/src/canvas/canvas-perf.ts +46 -7
  147. package/src/canvas/canvas-render.ts +1092 -220
  148. package/src/canvas/canvas-surface.ts +240 -0
  149. package/src/canvas/canvas-utils.ts +1166 -124
  150. package/src/canvas/iframe-drop.ts +2 -1
  151. package/src/canvas/iframe-entry.ts +241 -4
  152. package/src/canvas/iframe-host.ts +1226 -143
  153. package/src/canvas/iframe-inline-edit.ts +31 -0
  154. package/src/canvas/iframe-interaction.ts +76 -16
  155. package/src/canvas/iframe-keys.ts +107 -45
  156. package/src/canvas/iframe-overlay.ts +38 -1
  157. package/src/canvas/iframe-protocol.ts +137 -2
  158. package/src/canvas/iframe-render.ts +70 -2
  159. package/src/canvas/iframe-slash.ts +6 -0
  160. package/src/canvas/path-mapping.ts +56 -6
  161. package/src/canvas/surface-registry.ts +292 -0
  162. package/src/collab/collab-commands.ts +244 -0
  163. package/src/collab/collab-session.ts +198 -32
  164. package/src/collab/collab-state.ts +28 -2
  165. package/src/collab/presence-chips.ts +100 -9
  166. package/src/commands/active-registry.ts +42 -0
  167. package/src/commands/app-commands.ts +176 -0
  168. package/src/commands/budget.ts +158 -0
  169. package/src/commands/command-args.ts +253 -0
  170. package/src/commands/context.ts +387 -0
  171. package/src/commands/defaults.ts +580 -0
  172. package/src/commands/keymap.ts +571 -0
  173. package/src/commands/levels.ts +345 -0
  174. package/src/commands/live-context.ts +193 -0
  175. package/src/commands/reference.ts +227 -0
  176. package/src/commands/registry.ts +293 -0
  177. package/src/component-props.ts +3 -2
  178. package/src/content/draft-state.ts +106 -0
  179. package/src/content/entry-commands.ts +282 -0
  180. package/src/content/entry-editor.ts +327 -0
  181. package/src/content/entry-fields.ts +116 -0
  182. package/src/content/entry-model.ts +175 -0
  183. package/src/editor/canvas-context-menu.ts +17 -11
  184. package/src/editor/canvas-slash-bridge.ts +11 -4
  185. package/src/editor/context-menu.ts +804 -204
  186. package/src/editor/convert-to-component.ts +31 -10
  187. package/src/editor/convert-to-repeater.ts +3 -2
  188. package/src/editor/inline-edit-apply.ts +5 -5
  189. package/src/editor/inline-edit.ts +86 -50
  190. package/src/editor/insert-zone-action.ts +1 -1
  191. package/src/editor/shortcuts.ts +1043 -329
  192. package/src/editor/slash-menu.ts +1 -0
  193. package/src/files/elements.ts +166 -0
  194. package/src/files/file-ops.ts +178 -31
  195. package/src/files/files.ts +898 -268
  196. package/src/files/fs-events.ts +21 -0
  197. package/src/files/media-meta.ts +203 -0
  198. package/src/files/media-paths.ts +141 -0
  199. package/src/files/media-upload.ts +7 -3
  200. package/src/files/media-usage.ts +189 -0
  201. package/src/github/github-auth.ts +235 -33
  202. package/src/github/github-publish.ts +80 -21
  203. package/src/grid/grid-controller.ts +152 -12
  204. package/src/grid/grid-layout.ts +225 -20
  205. package/src/grid/grid-open.ts +120 -0
  206. package/src/grid/grid-panel.ts +554 -39
  207. package/src/grid/grid-source.ts +27 -1
  208. package/src/grid/redirects-grid.ts +599 -0
  209. package/src/grid/redirects.ts +398 -0
  210. package/src/grid/sources/content-source.ts +108 -2
  211. package/src/i18n/i18n-commands.ts +322 -0
  212. package/src/new-project/add-repo-modal.ts +8 -10
  213. package/src/new-project/import-tab.ts +34 -9
  214. package/src/new-project/location-fields.ts +9 -1
  215. package/src/new-project/new-project-modal.ts +270 -262
  216. package/src/packages/jxsuite-update.ts +97 -48
  217. package/src/packages/pull-package-sync.ts +18 -9
  218. package/src/page-params.ts +2 -1
  219. package/src/panels/activity-bar.ts +152 -91
  220. package/src/panels/activity-panel.ts +481 -0
  221. package/src/panels/ai-chat/chat-markdown.ts +8 -3
  222. package/src/panels/ai-chat/chat-view.ts +245 -18
  223. package/src/panels/ai-chat/composer.ts +31 -5
  224. package/src/panels/ai-chat/sessions-view.ts +17 -10
  225. package/src/panels/ai-panel.ts +279 -120
  226. package/src/panels/block-action-bar.ts +1115 -224
  227. package/src/panels/bottom-dock.ts +337 -0
  228. package/src/panels/canvas-dnd-bridge.ts +37 -8
  229. package/src/panels/chat-panel.ts +29 -12
  230. package/src/panels/data-explorer.ts +254 -112
  231. package/src/panels/data-grid.ts +10 -4
  232. package/src/panels/dnd.ts +28 -51
  233. package/src/panels/editors.ts +434 -107
  234. package/src/panels/elements-panel.ts +66 -2
  235. package/src/panels/empty-state.ts +112 -0
  236. package/src/panels/events-panel.ts +596 -82
  237. package/src/panels/formula-workspace.ts +408 -218
  238. package/src/panels/frontmatter-fields.ts +51 -10
  239. package/src/panels/frontmatter-panel.ts +357 -79
  240. package/src/panels/git-panel.ts +375 -164
  241. package/src/panels/head-panel.ts +791 -85
  242. package/src/panels/i18n-panel.ts +592 -0
  243. package/src/panels/imports-panel.ts +95 -85
  244. package/src/panels/jump-bar.ts +584 -0
  245. package/src/panels/layers-panel.ts +1106 -328
  246. package/src/panels/left-panel.ts +109 -204
  247. package/src/panels/navigator-panels.ts +131 -0
  248. package/src/panels/overlays.ts +7 -2
  249. package/src/panels/pane-context.ts +1477 -0
  250. package/src/panels/pane-grid.ts +406 -0
  251. package/src/panels/panel-registry.ts +340 -0
  252. package/src/panels/panel-scheduler.ts +75 -0
  253. package/src/panels/problems-panel.ts +234 -0
  254. package/src/panels/properties-panel.ts +946 -1139
  255. package/src/panels/provenance.ts +258 -0
  256. package/src/panels/quick-search.ts +791 -122
  257. package/src/panels/right-panel.ts +228 -102
  258. package/src/panels/seo-modal.ts +395 -0
  259. package/src/panels/settings-pane.ts +203 -0
  260. package/src/panels/signals-panel.ts +354 -137
  261. package/src/panels/statement-editor.ts +41 -25
  262. package/src/panels/statusbar.ts +342 -106
  263. package/src/panels/style-panel.ts +974 -463
  264. package/src/panels/style-utils.ts +3 -3
  265. package/src/panels/stylebook-doc.ts +4 -2
  266. package/src/panels/stylebook-layers-panel.ts +3 -2
  267. package/src/panels/stylebook-panel.ts +51 -26
  268. package/src/panels/tab-strip.ts +1058 -78
  269. package/src/panels/target-line.ts +274 -0
  270. package/src/panels/toolbar.ts +631 -484
  271. package/src/panels/welcome-screen.ts +301 -198
  272. package/src/platform-errors.ts +26 -3
  273. package/src/platform.ts +96 -2
  274. package/src/platforms/cloud.ts +71 -8
  275. package/src/platforms/devserver.ts +92 -29
  276. package/src/publish/deploy-checklist.ts +383 -0
  277. package/src/publish/pages-service.ts +10 -1
  278. package/src/publish/publish-commands.ts +218 -0
  279. package/src/publish/publish-panel.ts +110 -16
  280. package/src/recent-projects.ts +3 -2
  281. package/src/services/a11y-report.ts +505 -0
  282. package/src/services/ai-models.ts +75 -2
  283. package/src/services/ai-project-tools.ts +29 -10
  284. package/src/services/ai-system-prompt.ts +53 -14
  285. package/src/services/ai-tools.ts +39 -3
  286. package/src/services/ai-writes.ts +154 -0
  287. package/src/services/announce.ts +97 -0
  288. package/src/services/automation.ts +424 -175
  289. package/src/services/cem-export.ts +9 -4
  290. package/src/services/clock.ts +61 -0
  291. package/src/services/document-assistant.ts +36 -8
  292. package/src/services/idle.ts +179 -0
  293. package/src/services/import-client.ts +26 -0
  294. package/src/services/monaco-buffer.ts +627 -0
  295. package/src/services/monaco-lazy.ts +36 -0
  296. package/src/services/notify.ts +271 -0
  297. package/src/services/profile.ts +155 -0
  298. package/src/services/references.ts +0 -0
  299. package/src/services/token-lint.ts +3 -2
  300. package/src/services/tool-executor.ts +53 -7
  301. package/src/services/trusted-types.ts +123 -0
  302. package/src/settings/contexts-section.ts +427 -0
  303. package/src/settings/contributed-section.ts +149 -11
  304. package/src/settings/css-vars-editor.ts +306 -349
  305. package/src/settings/defs-editor.ts +93 -34
  306. package/src/settings/dependencies-editor.ts +7 -7
  307. package/src/settings/extension-sections.ts +37 -5
  308. package/src/settings/general-settings.ts +204 -121
  309. package/src/settings/locales-section.ts +347 -0
  310. package/src/settings/preferences-accounts.ts +140 -0
  311. package/src/settings/preferences-dialog.ts +620 -0
  312. package/src/settings/preferences-keymap.ts +270 -0
  313. package/src/settings/project-sections.ts +260 -0
  314. package/src/settings/section-registry.ts +169 -0
  315. package/src/settings/settings-document.ts +385 -0
  316. package/src/shell.ts +1549 -0
  317. package/src/site-context.ts +45 -20
  318. package/src/state.ts +14 -275
  319. package/src/store.ts +88 -43
  320. package/src/studio.ts +790 -346
  321. package/src/style/live-preview.ts +36 -0
  322. package/src/style/project-styles.ts +349 -0
  323. package/src/style/token-ref.ts +123 -0
  324. package/src/tabs/patch-ops.ts +16 -4
  325. package/src/tabs/project-config.ts +416 -0
  326. package/src/tabs/selection.ts +323 -0
  327. package/src/tabs/tab.ts +182 -47
  328. package/src/tabs/transact.ts +209 -28
  329. package/src/types.ts +68 -13
  330. package/src/ui/ai-credentials-form.ts +39 -35
  331. package/src/ui/ai-managed-connect.ts +113 -0
  332. package/src/ui/dynamic-slot.ts +224 -81
  333. package/src/ui/expression-editor.ts +71 -63
  334. package/src/ui/field-input.ts +4 -6
  335. package/src/ui/field-row.ts +215 -38
  336. package/src/ui/form-controls.ts +194 -7
  337. package/src/ui/layers.ts +492 -69
  338. package/src/ui/media-picker.ts +115 -25
  339. package/src/ui/panel-resize.ts +109 -91
  340. package/src/ui/progress-modal.ts +131 -50
  341. package/src/ui/regions.ts +462 -0
  342. package/src/ui/schema-form.ts +229 -45
  343. package/src/ui/spectrum.ts +24 -8
  344. package/src/ui/timing.ts +49 -0
  345. package/src/ui/value-selector.ts +20 -0
  346. package/src/ui/value-source.ts +348 -0
  347. package/src/ui/virtual-window.ts +400 -0
  348. package/src/utils/edit-display.ts +3 -2
  349. package/src/utils/inherited-style.ts +67 -37
  350. package/src/view.ts +64 -78
  351. package/src/workspace/pane-derive.ts +1258 -0
  352. package/src/workspace/session.ts +317 -0
  353. package/src/workspace/workspace.ts +1345 -23
  354. package/styles/canvas.css +653 -0
  355. package/styles/forced-colors.css +106 -0
  356. package/styles/inspector.css +1454 -0
  357. package/styles/overlays.css +2704 -0
  358. package/styles/panels.css +1701 -0
  359. package/styles/shell.css +1423 -0
  360. package/styles/tokens.css +151 -0
  361. package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
  362. package/dist/chunks/extension-sections-qct0gt8f.js +0 -531
  363. package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
  364. package/dist/chunks/files-02zn5y24.js +0 -50
  365. package/dist/chunks/files-02zn5y24.js.map +0 -9
  366. package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
  367. package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
  368. package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
  369. package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
  370. package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
  371. package/dist/chunks/settings-modal-gj0hrah4.js.map +0 -9
  372. package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
  373. package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
  374. package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
  375. package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
  376. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
  377. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
  378. package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
  379. package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
  380. package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
  381. package/dist/chunks/studio-568nx4t5.js +0 -469
  382. package/dist/chunks/studio-568nx4t5.js.map +0 -14
  383. package/dist/chunks/studio-9smfzqhc.js +0 -19
  384. package/dist/chunks/studio-9smfzqhc.js.map +0 -10
  385. package/dist/chunks/studio-asvf0j9e.js +0 -429
  386. package/dist/chunks/studio-asvf0j9e.js.map +0 -13
  387. package/dist/chunks/studio-d77qm3pk.js +0 -3427
  388. package/dist/chunks/studio-d77qm3pk.js.map +0 -26
  389. package/dist/chunks/studio-j6gqyjf4.js +0 -1854
  390. package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
  391. package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
  392. package/dist/chunks/studio-qkvt37c0.js.map +0 -9
  393. package/dist/chunks/studio-rq0vxb19.js +0 -3744
  394. package/dist/chunks/studio-rq0vxb19.js.map +0 -22
  395. package/dist/chunks/studio-wd6ewdvd.js +0 -853
  396. package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
  397. package/dist/chunks/studio-xq0t7n5t.js +0 -140
  398. package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
  399. package/dist/chunks/studio-xze4zrs1.js.map +0 -10
  400. package/dist/chunks/studio-ygzav7z5.js.map +0 -46
  401. package/dist/chunks/studio-zmy7241e.js +0 -399
  402. package/dist/chunks/studio-zmy7241e.js.map +0 -12
  403. package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
  404. package/src/browse/browse-modal.ts +0 -69
  405. package/src/browse/browse.ts +0 -904
  406. package/src/canvas/canvas-diff.ts +0 -216
  407. package/src/canvas/nested-site-style.ts +0 -58
  408. package/src/new-project/design-fields.ts +0 -264
  409. package/src/new-project/templates.ts +0 -61
  410. package/src/panels/tab-bar.ts +0 -548
  411. package/src/settings/settings-modal.ts +0 -203
  412. /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
  413. /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
  414. /package/dist/chunks/{format-host-2c188n41.js.map → format-host-mkwsmt8d.js.map} +0 -0
  415. /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
  416. /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
  417. /package/dist/chunks/{studio-hhj92gcr.js.map → studio-s519zc99.js.map} +0 -0
  418. /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
  419. /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
@@ -1,1854 +0,0 @@
1
- import {
2
- openFileInTab
3
- } from "./studio-d77qm3pk.js";
4
- import {
5
- getEffectiveMedia,
6
- postSiteStyleToLiveHosts,
7
- pureSchemeOf,
8
- updateSiteConfig
9
- } from "./studio-ygzav7z5.js";
10
- import {
11
- classMap
12
- } from "./studio-cx91mnh8.js";
13
- import {
14
- VERSION,
15
- isComparable,
16
- isUpgrade,
17
- showProgressModal,
18
- stripRange
19
- } from "./studio-568nx4t5.js";
20
- import {
21
- openModal,
22
- statusMessage
23
- } from "./studio-asvf0j9e.js";
24
- import {
25
- camelToLabel,
26
- friendlyNameToVar,
27
- projectState,
28
- varDisplayName
29
- } from "./studio-rq0vxb19.js";
30
- import {
31
- ref
32
- } from "./studio-4k0m4fmp.js";
33
- import {
34
- html,
35
- nothing,
36
- render
37
- } from "./studio-5x5774ak.js";
38
- import {
39
- getPlatform
40
- } from "./studio-9smfzqhc.js";
41
- import {
42
- __require
43
- } from "./studio-md4gps17.js";
44
-
45
- // src/settings/schema-field-ui.ts
46
- var FIELD_TYPES = ["string", "number", "boolean", "array", "object", "reference"];
47
- var FORMAT_OPTIONS = ["", "image", "date", "color"];
48
- function detectFieldType(schema) {
49
- if (schema.$ref) {
50
- return "reference";
51
- }
52
- return schema.type || "string";
53
- }
54
- function detectFieldFormat(schema) {
55
- if (schema.type === "array" && schema.items?.format) {
56
- return schema.items.format;
57
- }
58
- return schema.format || "";
59
- }
60
- function fieldCardTpl(fieldName, fieldSchema, isRequired, handlers, contentTypeNames = []) {
61
- const type = detectFieldType(fieldSchema);
62
- const format = detectFieldFormat(fieldSchema);
63
- const isNested = type === "object";
64
- const isRef = type === "reference";
65
- const nestedProps = fieldSchema.properties || {};
66
- const nestedRequired = fieldSchema.required || [];
67
- const refTarget = fieldSchema.$ref ? fieldSchema.$ref.replace(/^#\/[^/]+\//, "") : "";
68
- return html`
69
- <div class="schema-field-card">
70
- <div class="schema-field-row">
71
- <sp-field-label size="s" class="schema-field-label"
72
- >${camelToLabel(fieldName)}</sp-field-label
73
- >
74
- <sp-textfield
75
- size="s"
76
- quiet
77
- value=${fieldName}
78
- class="schema-field-name-input"
79
- @change=${(e) => {
80
- const target = e.target;
81
- const newName = target.value.trim();
82
- if (newName && newName !== fieldName) {
83
- handlers.onRename(fieldName, newName);
84
- } else {
85
- target.value = fieldName;
86
- }
87
- }}
88
- @keydown=${(e) => {
89
- const target = e.target;
90
- if (e.key === "Enter") {
91
- target.blur();
92
- }
93
- if (e.key === "Escape") {
94
- target.value = fieldName;
95
- target.blur();
96
- }
97
- }}
98
- ></sp-textfield>
99
- ${typePickerTpl(type, (newType) => handlers.onChangeType(fieldName, newType))}
100
- ${type === "string" || type === "array" ? formatPickerTpl(format, (f) => {
101
- if (handlers.onChangeFormat) {
102
- handlers.onChangeFormat(fieldName, f);
103
- }
104
- }) : nothing}
105
- <sp-switch
106
- size="s"
107
- ?checked=${isRequired}
108
- @change=${() => handlers.onToggleRequired(fieldName)}
109
- >
110
- Req
111
- </sp-switch>
112
- <sp-action-button
113
- size="xs"
114
- quiet
115
- title="Delete field"
116
- @click=${() => handlers.onDelete(fieldName)}
117
- >
118
- <sp-icon-delete slot="icon"></sp-icon-delete>
119
- </sp-action-button>
120
- </div>
121
- ${isRef && contentTypeNames.length > 0 ? html`
122
- <div class="schema-field-ref-target">
123
- <sp-picker
124
- size="s"
125
- label="Target"
126
- value=${refTarget}
127
- @change=${(e) => {
128
- if (handlers.onChangeRefTarget) {
129
- handlers.onChangeRefTarget(fieldName, e.target.value);
130
- }
131
- }}
132
- >
133
- ${contentTypeNames.map((n) => html`<sp-menu-item value=${n}>${n}</sp-menu-item>`)}
134
- </sp-picker>
135
- </div>
136
- ` : nothing}
137
- ${isNested ? html`
138
- <div class="schema-field-nested">
139
- ${Object.entries(nestedProps).map(([name, sub]) => nestedFieldCardTpl(fieldName, name, sub, nestedRequired.includes(name), handlers))}
140
- ${nestedAddFieldTpl(fieldName, handlers)}
141
- </div>
142
- ` : nothing}
143
- </div>
144
- `;
145
- }
146
- function nestedFieldCardTpl(parentName, childName, childSchema, isRequired, handlers) {
147
- const type = detectFieldType(childSchema);
148
- const format = detectFieldFormat(childSchema);
149
- return html`
150
- <div class="schema-field-card schema-field-card--nested">
151
- <div class="schema-field-row">
152
- <sp-textfield
153
- size="s"
154
- quiet
155
- value=${childName}
156
- class="schema-field-name-input"
157
- @change=${(e) => {
158
- const target = e.target;
159
- const newName = target.value.trim();
160
- if (newName && newName !== childName && handlers.onRenameNested) {
161
- handlers.onRenameNested(parentName, childName, newName);
162
- } else {
163
- target.value = childName;
164
- }
165
- }}
166
- @keydown=${(e) => {
167
- const target = e.target;
168
- if (e.key === "Enter") {
169
- target.blur();
170
- }
171
- if (e.key === "Escape") {
172
- target.value = childName;
173
- target.blur();
174
- }
175
- }}
176
- ></sp-textfield>
177
- ${typePickerTpl(type, (newType) => {
178
- if (handlers.onChangeNestedType) {
179
- handlers.onChangeNestedType(parentName, childName, newType);
180
- }
181
- })}
182
- ${type === "string" || type === "array" ? formatPickerTpl(format, (f) => {
183
- if (handlers.onChangeNestedFormat) {
184
- handlers.onChangeNestedFormat(parentName, childName, f);
185
- }
186
- }) : nothing}
187
- <sp-switch
188
- size="s"
189
- ?checked=${isRequired}
190
- @change=${() => {
191
- if (handlers.onToggleNestedRequired) {
192
- handlers.onToggleNestedRequired(parentName, childName);
193
- }
194
- }}
195
- >
196
- Req
197
- </sp-switch>
198
- <sp-action-button
199
- size="xs"
200
- quiet
201
- title="Delete field"
202
- @click=${() => {
203
- if (handlers.onDeleteNested) {
204
- handlers.onDeleteNested(parentName, childName);
205
- }
206
- }}
207
- >
208
- <sp-icon-delete slot="icon"></sp-icon-delete>
209
- </sp-action-button>
210
- </div>
211
- </div>
212
- `;
213
- }
214
- function nestedAddFieldTpl(parentName, handlers) {
215
- return html`
216
- <div class="schema-nested-add">
217
- <sp-textfield
218
- size="s"
219
- placeholder="field name"
220
- class="schema-nested-add-name"
221
- @keydown=${(e) => {
222
- if (e.key === "Enter") {
223
- const target = e.target;
224
- const row = target.closest(".schema-nested-add");
225
- const name = target.value.trim();
226
- const typePicker = row?.querySelector("sp-picker");
227
- const type = typePicker?.value || "string";
228
- if (name && handlers.onAddNestedField) {
229
- handlers.onAddNestedField(parentName, {
230
- name,
231
- required: false,
232
- type
233
- });
234
- target.value = "";
235
- }
236
- }
237
- }}
238
- ></sp-textfield>
239
- ${typePickerTpl("string", () => {})}
240
- <sp-action-button
241
- size="xs"
242
- quiet
243
- title="Add nested field"
244
- @click=${(e) => {
245
- const target = e.target;
246
- const row = target.closest(".schema-nested-add");
247
- const nameInput = row?.querySelector(".schema-nested-add-name");
248
- const typePicker = row?.querySelector("sp-picker");
249
- const name = nameInput?.value?.trim();
250
- const type = typePicker?.value || "string";
251
- if (name && handlers.onAddNestedField) {
252
- handlers.onAddNestedField(parentName, {
253
- name,
254
- required: false,
255
- type
256
- });
257
- if (nameInput) {
258
- nameInput.value = "";
259
- }
260
- }
261
- }}
262
- >
263
- <sp-icon-add slot="icon"></sp-icon-add>
264
- </sp-action-button>
265
- </div>
266
- `;
267
- }
268
- function typePickerTpl(value, onChange) {
269
- return html`
270
- <sp-picker
271
- size="s"
272
- label="Type"
273
- value=${value}
274
- @change=${(e) => onChange(e.target.value)}
275
- >
276
- ${FIELD_TYPES.map((t) => html`<sp-menu-item value=${t}>${t}</sp-menu-item>`)}
277
- </sp-picker>
278
- `;
279
- }
280
- function formatPickerTpl(value, onChange) {
281
- return html`
282
- <sp-picker
283
- size="s"
284
- label="Format"
285
- value=${value}
286
- @change=${(e) => onChange(e.target.value)}
287
- >
288
- ${FORMAT_OPTIONS.map((f) => html`<sp-menu-item value=${f}>${f || "(none)"}</sp-menu-item>`)}
289
- </sp-picker>
290
- `;
291
- }
292
- function addFieldFormTpl(state, handlers) {
293
- return html`
294
- <div class="schema-add-field">
295
- <sp-textfield
296
- size="s"
297
- placeholder="Field name"
298
- .value=${state.name}
299
- @input=${(e) => handlers.onInput("name", e.target.value)}
300
- @keydown=${(e) => {
301
- if (e.key === "Enter") {
302
- handlers.onConfirm();
303
- }
304
- if (e.key === "Escape") {
305
- handlers.onCancel();
306
- }
307
- }}
308
- ></sp-textfield>
309
- ${typePickerTpl(state.type, (t) => handlers.onInput("type", t))}
310
- ${state.type === "string" || state.type === "array" ? formatPickerTpl(state.format || "", (f) => handlers.onInput("format", f)) : nothing}
311
- <sp-switch
312
- size="s"
313
- ?checked=${state.required}
314
- @change=${(e) => handlers.onInput("required", e.target.checked)}
315
- >
316
- Required
317
- </sp-switch>
318
- <sp-action-button size="s" @click=${handlers.onConfirm}>Add</sp-action-button>
319
- <sp-action-button size="s" quiet @click=${handlers.onCancel}>Cancel</sp-action-button>
320
- </div>
321
- `;
322
- }
323
- function schemaForType(type, format) {
324
- switch (type) {
325
- case "number": {
326
- return { type: "number" };
327
- }
328
- case "boolean": {
329
- return { type: "boolean" };
330
- }
331
- case "array": {
332
- return format ? { items: { format, type: "string" }, type: "array" } : { items: { type: "string" }, type: "array" };
333
- }
334
- case "object": {
335
- return { properties: {}, required: [], type: "object" };
336
- }
337
- case "reference": {
338
- return { $ref: "#/content/" };
339
- }
340
- default: {
341
- return format ? { format, type: "string" } : { type: "string" };
342
- }
343
- }
344
- }
345
- function yamlDefault(type, format) {
346
- if (format === "date") {
347
- return new Date().toISOString().split("T")[0];
348
- }
349
- if (format === "image") {
350
- return '""';
351
- }
352
- switch (type) {
353
- case "boolean": {
354
- return "false";
355
- }
356
- case "number": {
357
- return "0";
358
- }
359
- case "array": {
360
- return "[]";
361
- }
362
- case "object": {
363
- return "{}";
364
- }
365
- default: {
366
- return '""';
367
- }
368
- }
369
- }
370
-
371
- // src/settings/defs-editor.ts
372
- var selectedDef = null;
373
- var showAddField = false;
374
- var newFieldState = { format: "", name: "", required: false, type: "string" };
375
- var showNewDef = false;
376
- var newDefName = "";
377
- async function saveProjectConfig() {
378
- const platform = getPlatform();
379
- const config = projectState.projectConfig;
380
- await platform.writeFile("project.json", JSON.stringify(config, null, "\t"));
381
- }
382
- function getSelectedDef() {
383
- const config = projectState?.projectConfig;
384
- return config?.$defs?.[selectedDef];
385
- }
386
- function handleNewDef(rerender) {
387
- const name = newDefName.trim();
388
- if (!name) {
389
- return;
390
- }
391
- const config = projectState?.projectConfig;
392
- if (!config) {
393
- return;
394
- }
395
- if (!config.$defs) {
396
- config.$defs = {};
397
- }
398
- if (config.$defs[name]) {
399
- return;
400
- }
401
- config.$defs[name] = {
402
- properties: {},
403
- required: [],
404
- type: "object"
405
- };
406
- selectedDef = name;
407
- showNewDef = false;
408
- newDefName = "";
409
- rerender();
410
- saveProjectConfig();
411
- }
412
- function handleAddField(rerender) {
413
- const name = newFieldState.name.trim();
414
- if (!name || !selectedDef) {
415
- return;
416
- }
417
- const def = getSelectedDef();
418
- if (!def) {
419
- return;
420
- }
421
- if (!def.properties) {
422
- def.properties = {};
423
- }
424
- def.properties[name] = schemaForType(newFieldState.type, newFieldState.format || undefined);
425
- if (newFieldState.required) {
426
- if (!def.required) {
427
- def.required = [];
428
- }
429
- if (!def.required.includes(name)) {
430
- def.required.push(name);
431
- }
432
- }
433
- showAddField = false;
434
- newFieldState = { format: "", name: "", required: false, type: "string" };
435
- rerender();
436
- saveProjectConfig();
437
- }
438
- function handleDeleteField(fieldName, rerender) {
439
- const def = getSelectedDef();
440
- if (!def?.properties) {
441
- return;
442
- }
443
- delete def.properties[fieldName];
444
- if (def.required) {
445
- def.required = def.required.filter((r) => r !== fieldName);
446
- }
447
- rerender();
448
- saveProjectConfig();
449
- }
450
- function handleToggleRequired(fieldName, rerender) {
451
- const def = getSelectedDef();
452
- if (!def) {
453
- return;
454
- }
455
- if (!def.required) {
456
- def.required = [];
457
- }
458
- const idx = def.required.indexOf(fieldName);
459
- if (idx !== -1) {
460
- def.required.splice(idx, 1);
461
- } else {
462
- def.required.push(fieldName);
463
- }
464
- rerender();
465
- saveProjectConfig();
466
- }
467
- function handleRenameField(oldName, newName, rerender) {
468
- const def = getSelectedDef();
469
- if (!def?.properties || !newName || def.properties[newName]) {
470
- return;
471
- }
472
- const newProps = {};
473
- for (const [key, val] of Object.entries(def.properties)) {
474
- newProps[key === oldName ? newName : key] = val;
475
- }
476
- def.properties = newProps;
477
- if (def.required) {
478
- def.required = def.required.map((r) => r === oldName ? newName : r);
479
- }
480
- rerender();
481
- saveProjectConfig();
482
- }
483
- function handleChangeType(fieldName, newType, rerender) {
484
- const def = getSelectedDef();
485
- if (!def?.properties?.[fieldName]) {
486
- return;
487
- }
488
- const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(def.properties[fieldName]) : undefined;
489
- def.properties[fieldName] = schemaForType(newType, oldFormat || undefined);
490
- rerender();
491
- saveProjectConfig();
492
- }
493
- function handleChangeFormat(fieldName, format, rerender) {
494
- const def = getSelectedDef();
495
- if (!def?.properties?.[fieldName]) {
496
- return;
497
- }
498
- const prop = def.properties[fieldName];
499
- const type = prop.type || "string";
500
- def.properties[fieldName] = schemaForType(type, format || undefined);
501
- rerender();
502
- saveProjectConfig();
503
- }
504
- function handleAddNestedField(parentName, fieldState, rerender) {
505
- const def = getSelectedDef();
506
- const parent = def?.properties?.[parentName];
507
- if (!parent) {
508
- return;
509
- }
510
- if (!parent.properties) {
511
- parent.properties = {};
512
- }
513
- parent.properties[fieldState.name] = schemaForType(fieldState.type);
514
- if (fieldState.required) {
515
- if (!parent.required) {
516
- parent.required = [];
517
- }
518
- if (!parent.required.includes(fieldState.name)) {
519
- parent.required.push(fieldState.name);
520
- }
521
- }
522
- rerender();
523
- saveProjectConfig();
524
- }
525
- function handleDeleteNested(parentName, childName, rerender) {
526
- const def = getSelectedDef();
527
- const parent = def?.properties?.[parentName];
528
- if (!parent?.properties) {
529
- return;
530
- }
531
- delete parent.properties[childName];
532
- if (parent.required) {
533
- parent.required = parent.required.filter((r) => r !== childName);
534
- }
535
- rerender();
536
- saveProjectConfig();
537
- }
538
- function handleToggleNestedRequired(parentName, childName, rerender) {
539
- const def = getSelectedDef();
540
- const parent = def?.properties?.[parentName];
541
- if (!parent) {
542
- return;
543
- }
544
- if (!parent.required) {
545
- parent.required = [];
546
- }
547
- const idx = parent.required.indexOf(childName);
548
- if (idx !== -1) {
549
- parent.required.splice(idx, 1);
550
- } else {
551
- parent.required.push(childName);
552
- }
553
- rerender();
554
- saveProjectConfig();
555
- }
556
- function handleRenameNested(parentName, oldChild, newChild, rerender) {
557
- const def = getSelectedDef();
558
- const parent = def?.properties?.[parentName];
559
- if (!parent?.properties || !newChild || parent.properties[newChild]) {
560
- return;
561
- }
562
- const newProps = {};
563
- for (const [key, val] of Object.entries(parent.properties)) {
564
- newProps[key === oldChild ? newChild : key] = val;
565
- }
566
- parent.properties = newProps;
567
- if (parent.required) {
568
- parent.required = parent.required.map((r) => r === oldChild ? newChild : r);
569
- }
570
- rerender();
571
- saveProjectConfig();
572
- }
573
- function handleChangeNestedType(parentName, childName, newType, rerender) {
574
- const def = getSelectedDef();
575
- const parent = def?.properties?.[parentName];
576
- if (!parent?.properties?.[childName]) {
577
- return;
578
- }
579
- const oldFormat = newType === "string" || newType === "array" ? detectFieldFormat(parent.properties[childName]) : undefined;
580
- parent.properties[childName] = schemaForType(newType, oldFormat || undefined);
581
- rerender();
582
- saveProjectConfig();
583
- }
584
- function handleChangeNestedFormat(parentName, childName, format, rerender) {
585
- const def = getSelectedDef();
586
- const parent = def?.properties?.[parentName];
587
- if (!parent?.properties?.[childName]) {
588
- return;
589
- }
590
- const prop = parent.properties[childName];
591
- const type = prop.type || "string";
592
- parent.properties[childName] = schemaForType(type, format || undefined);
593
- rerender();
594
- saveProjectConfig();
595
- }
596
- function handleDeleteDef(rerender) {
597
- if (!selectedDef) {
598
- return;
599
- }
600
- const config = projectState?.projectConfig;
601
- if (!config?.$defs?.[selectedDef]) {
602
- return;
603
- }
604
- delete config.$defs[selectedDef];
605
- selectedDef = null;
606
- rerender();
607
- saveProjectConfig();
608
- }
609
- function renderDefsEditor(container) {
610
- const rerender = () => renderDefsEditor(container);
611
- const config = projectState?.projectConfig;
612
- const defs = config?.$defs || {};
613
- const defNames = Object.keys(defs);
614
- const listTpl = html`
615
- <div class="settings-list-panel">
616
- ${defNames.map((name) => html`
617
- <sp-action-button
618
- size="s"
619
- ?selected=${selectedDef === name}
620
- @click=${() => {
621
- selectedDef = name;
622
- showAddField = false;
623
- rerender();
624
- }}
625
- >
626
- ${name}
627
- </sp-action-button>
628
- `)}
629
- ${showNewDef ? html`
630
- <div class="settings-inline-form">
631
- <sp-textfield
632
- size="s"
633
- placeholder="TypeName"
634
- .value=${newDefName}
635
- @input=${(e) => {
636
- newDefName = e.target.value;
637
- }}
638
- @keydown=${(e) => {
639
- if (e.key === "Enter") {
640
- handleNewDef(rerender);
641
- }
642
- if (e.key === "Escape") {
643
- showNewDef = false;
644
- rerender();
645
- }
646
- }}
647
- ></sp-textfield>
648
- <sp-action-button size="s" @click=${() => handleNewDef(rerender)}>
649
- Create
650
- </sp-action-button>
651
- </div>
652
- ` : html`
653
- <sp-action-button
654
- size="s"
655
- quiet
656
- @click=${() => {
657
- showNewDef = true;
658
- rerender();
659
- }}
660
- >
661
- <sp-icon-add slot="icon"></sp-icon-add> New Definition
662
- </sp-action-button>
663
- `}
664
- </div>
665
- `;
666
- let editorTpl;
667
- if (!selectedDef || !defs[selectedDef]) {
668
- editorTpl = html`<div class="settings-empty-state">Select or create a type definition</div>`;
669
- } else {
670
- const def = defs[selectedDef];
671
- const properties = def.properties || {};
672
- const required = def.required || [];
673
- const handlers = {
674
- onAddNestedField: (p, s) => handleAddNestedField(p, s, rerender),
675
- onChangeFormat: (n, f) => handleChangeFormat(n, f, rerender),
676
- onChangeNestedFormat: (p, c, f) => handleChangeNestedFormat(p, c, f, rerender),
677
- onChangeNestedType: (p, c, t) => handleChangeNestedType(p, c, t, rerender),
678
- onChangeType: (n, t) => handleChangeType(n, t, rerender),
679
- onDelete: (n) => handleDeleteField(n, rerender),
680
- onDeleteNested: (p, c) => handleDeleteNested(p, c, rerender),
681
- onRename: (oldN, newN) => handleRenameField(oldN, newN, rerender),
682
- onRenameNested: (p, o, n) => handleRenameNested(p, o, n, rerender),
683
- onToggleNestedRequired: (p, c) => handleToggleNestedRequired(p, c, rerender),
684
- onToggleRequired: (n) => handleToggleRequired(n, rerender)
685
- };
686
- const fieldCards = Object.entries(properties).map(([name, fieldDef]) => fieldCardTpl(name, fieldDef, required.includes(name), handlers));
687
- editorTpl = html`
688
- <div class="settings-editor-panel">
689
- <div class="settings-editor-header">
690
- <h3>${selectedDef}</h3>
691
- <sp-action-button
692
- size="xs"
693
- quiet
694
- title="Delete definition"
695
- @click=${() => handleDeleteDef(rerender)}
696
- >
697
- <sp-icon-delete slot="icon"></sp-icon-delete>
698
- </sp-action-button>
699
- </div>
700
- <div class="schema-field-list">${fieldCards}</div>
701
- ${showAddField ? addFieldFormTpl(newFieldState, {
702
- onCancel: () => {
703
- showAddField = false;
704
- newFieldState = {
705
- format: "",
706
- name: "",
707
- required: false,
708
- type: "string"
709
- };
710
- rerender();
711
- },
712
- onConfirm: () => handleAddField(rerender),
713
- onInput: (field, value) => {
714
- newFieldState = { ...newFieldState, [field]: value };
715
- rerender();
716
- }
717
- }) : html`
718
- <sp-action-button
719
- size="s"
720
- quiet
721
- @click=${() => {
722
- showAddField = true;
723
- rerender();
724
- }}
725
- >
726
- <sp-icon-add slot="icon"></sp-icon-add> Add Field
727
- </sp-action-button>
728
- `}
729
- </div>
730
- `;
731
- }
732
- const tpl = html` <div class="settings-two-col">${listTpl} ${editorTpl}</div> `;
733
- render(tpl, container);
734
- }
735
-
736
- // src/utils/canvas-media.ts
737
- function isSchemeQuery(query) {
738
- return pureSchemeOf(query) !== null;
739
- }
740
- function schemeOfQuery(query) {
741
- return pureSchemeOf(query);
742
- }
743
- function parseMediaEntries(mediaDef) {
744
- if (!mediaDef) {
745
- return { baseWidth: 320, featureQueries: [], sizeBreakpoints: [] };
746
- }
747
- const features = [];
748
- const sizes = [];
749
- let baseWidth = 320;
750
- for (const [name, query] of Object.entries(mediaDef)) {
751
- if (name === "--") {
752
- const wm = String(query).match(/^(\d+)\s*px$/);
753
- baseWidth = wm ? Number(wm[1]) : 320;
754
- continue;
755
- }
756
- const minMatch = query.match(/min-width:\s*([\d.]+)px/);
757
- const maxMatch = query.match(/max-width:\s*([\d.]+)px/);
758
- if (minMatch) {
759
- sizes.push({ name, query, type: "min", width: Number(minMatch[1]) });
760
- } else if (maxMatch) {
761
- sizes.push({ name, query, type: "max", width: Number(maxMatch[1]) });
762
- } else {
763
- features.push({ name, query });
764
- }
765
- }
766
- sizes.sort((a, b) => a.type === "min" ? a.width - b.width : b.width - a.width);
767
- return { baseWidth, featureQueries: features, sizeBreakpoints: sizes };
768
- }
769
-
770
- // src/settings/css-vars-editor.ts
771
- function renderCssVarsEditor(container) {
772
- const config = projectState?.projectConfig || {};
773
- const rootStyle = config.style || {};
774
- const media = getEffectiveMedia(config.$media);
775
- const groups = { color: [], font: [], other: [], size: [] };
776
- for (const [k, v] of Object.entries(rootStyle)) {
777
- if (!k.startsWith("--")) {
778
- continue;
779
- }
780
- if (typeof v !== "string" && typeof v !== "number") {
781
- continue;
782
- }
783
- if (k.startsWith("--color")) {
784
- groups.color.push([k, v]);
785
- } else if (k.startsWith("--font")) {
786
- groups.font.push([k, v]);
787
- } else if (k.startsWith("--size") || k.startsWith("--spacing") || k.startsWith("--radius")) {
788
- groups.size.push([k, v]);
789
- } else {
790
- groups.other.push([k, v]);
791
- }
792
- }
793
- const mediaNames = media ? Object.keys(media).filter((m) => m !== "--" && !isSchemeQuery(String(media[m]))) : [];
794
- const schemeEntries = media ? Object.entries(media).flatMap(([name, query]) => {
795
- const scheme = schemeOfQuery(String(query));
796
- return scheme ? [{ name, scheme }] : [];
797
- }) : [];
798
- const save = () => {
799
- updateSiteConfig({ style: { ...rootStyle } });
800
- postSiteStyleToLiveHosts();
801
- };
802
- const updateVar = (name, val) => {
803
- rootStyle[name] = val;
804
- save();
805
- };
806
- const updateSchemeVar = (schemeName, varName, val) => {
807
- const key = `@${schemeName}`;
808
- if (val) {
809
- const block = rootStyle[key] ??= {};
810
- block[varName] = val;
811
- } else {
812
- const block = rootStyle[key];
813
- if (block && typeof block === "object") {
814
- delete block[varName];
815
- if (Object.keys(block).length === 0) {
816
- delete rootStyle[key];
817
- }
818
- }
819
- }
820
- save();
821
- renderCssVarsEditor(container);
822
- };
823
- const enableDarkScheme = () => {
824
- updateSiteConfig({
825
- $media: { ...config.$media, "--dark": "(prefers-color-scheme: dark)" }
826
- }).then(() => renderCssVarsEditor(container));
827
- };
828
- const deleteVar = (name) => {
829
- delete rootStyle[name];
830
- save();
831
- renderCssVarsEditor(container);
832
- };
833
- const addVar = (prefix, friendlyName, val) => {
834
- const varName = friendlyNameToVar(friendlyName, prefix);
835
- if (!varName || !val) {
836
- return;
837
- }
838
- rootStyle[varName] = val;
839
- save();
840
- renderCssVarsEditor(container);
841
- };
842
- const tpl = html`
843
- <div class="settings-section">
844
- <h3 class="settings-section-title">CSS Variables</h3>
845
-
846
- ${renderColorSection(groups.color, updateVar, deleteVar, addVar, rootStyle, schemeEntries, updateSchemeVar, enableDarkScheme)}
847
- ${renderFontSection(groups.font, updateVar, deleteVar, addVar)}
848
- ${renderSizeSection(groups.size, updateVar, deleteVar, addVar, rootStyle, mediaNames)}
849
- ${groups.other.length > 0 ? renderOtherSection(groups.other, updateVar, deleteVar, addVar, rootStyle, mediaNames) : nothing}
850
- </div>
851
- `;
852
- render(tpl, container);
853
- }
854
- function renderColorSection(vars, updateVar, deleteVar, addVar, rootStyle, schemeEntries, updateSchemeVar, enableDarkScheme) {
855
- return html`
856
- <div class="css-vars-group">
857
- <h4 class="css-vars-group-title">Colors</h4>
858
- ${vars.map(([name, val]) => html`
859
- <div class="css-var-row">
860
- <div class="css-var-swatch" style="background:${val}">
861
- <input
862
- type="color"
863
- .value=${val && String(val).startsWith("#") ? val : "#3b82f6"}
864
- @input=${(e) => updateVar(name, e.target.value)}
865
- />
866
- </div>
867
- <span class="css-var-name">${varDisplayName(name, "--color-")}</span>
868
- <sp-textfield
869
- size="s"
870
- .value=${String(val)}
871
- @change=${(e) => updateVar(name, e.target.value)}
872
- style="flex:1;max-width:160px"
873
- ></sp-textfield>
874
- <sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
875
- <sp-icon-delete slot="icon"></sp-icon-delete>
876
- </sp-action-button>
877
- </div>
878
- ${schemeEntries.map((entry) => renderSchemeOverride(name, rootStyle, entry, updateSchemeVar))}
879
- `)}
880
- ${renderAddRow("--color-", "Primary Blue", "#3b82f6", addVar)}
881
- ${schemeEntries.length === 0 ? html`
882
- <sp-action-button
883
- size="s"
884
- class="css-vars-enable-dark"
885
- title="Add a dark color scheme: declares --dark in $media so every color token can carry a dark value"
886
- @click=${enableDarkScheme}
887
- >
888
- Enable dark scheme
889
- </sp-action-button>
890
- ` : nothing}
891
- </div>
892
- `;
893
- }
894
- function renderSchemeOverride(varName, rootStyle, entry, updateSchemeVar) {
895
- const block = rootStyle[`@${entry.name}`];
896
- const current = block && typeof block === "object" ? block[varName] : undefined;
897
- const label = entry.scheme === "dark" ? "Dark" : "Light";
898
- return html`
899
- <div class="css-var-media-row css-var-scheme-row">
900
- <span class="css-var-media-label">${label}</span>
901
- <div class="css-var-swatch" style="background:${current ?? "transparent"}">
902
- <input
903
- type="color"
904
- .value=${current && String(current).startsWith("#") ? String(current) : "#111111"}
905
- @input=${(e) => updateSchemeVar(entry.name, varName, e.target.value)}
906
- />
907
- </div>
908
- <sp-textfield
909
- size="s"
910
- placeholder="inherits"
911
- .value=${current == null ? "" : String(current)}
912
- @change=${(e) => updateSchemeVar(entry.name, varName, e.target.value)}
913
- style="flex:1;max-width:160px"
914
- ></sp-textfield>
915
- </div>
916
- `;
917
- }
918
- function renderFontSection(vars, updateVar, deleteVar, addVar) {
919
- return html`
920
- <div class="css-vars-group">
921
- <h4 class="css-vars-group-title">Fonts</h4>
922
- ${vars.map(([name, val]) => html`
923
- <div class="css-var-row">
924
- <span class="css-var-name">${varDisplayName(name, "--font-")}</span>
925
- <sp-textfield
926
- size="s"
927
- .value=${String(val)}
928
- @change=${(e) => updateVar(name, e.target.value)}
929
- style="flex:1"
930
- ></sp-textfield>
931
- <sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
932
- <sp-icon-delete slot="icon"></sp-icon-delete>
933
- </sp-action-button>
934
- </div>
935
- <div class="css-var-font-preview" style="font-family:${val}">
936
- The quick brown fox jumps over the lazy dog
937
- </div>
938
- `)}
939
- ${renderAddRow("--font-", "Body Serif", "'Georgia', serif", addVar)}
940
- </div>
941
- `;
942
- }
943
- function renderSizeSection(vars, updateVar, deleteVar, addVar, rootStyle, mediaNames) {
944
- return html`
945
- <div class="css-vars-group">
946
- <h4 class="css-vars-group-title">Sizes &amp; Spacing</h4>
947
- ${vars.map(([name, val]) => html`
948
- <div class="css-var-row">
949
- <span class="css-var-name"
950
- >${varDisplayName(name, "--size-") || varDisplayName(name, "--spacing-") || varDisplayName(name, "--radius-") || name}</span
951
- >
952
- <sp-textfield
953
- size="s"
954
- .value=${String(val)}
955
- @change=${(e) => updateVar(name, e.target.value)}
956
- style="max-width:120px"
957
- ></sp-textfield>
958
- <sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
959
- <sp-icon-delete slot="icon"></sp-icon-delete>
960
- </sp-action-button>
961
- </div>
962
- ${mediaNames.length > 0 ? renderMediaOverrides(name, rootStyle, mediaNames) : nothing}
963
- `)}
964
- ${renderAddRow("--size-", "Spacing Large", "32px", addVar)}
965
- </div>
966
- `;
967
- }
968
- function renderOtherSection(vars, updateVar, deleteVar, addVar, rootStyle, mediaNames) {
969
- return html`
970
- <div class="css-vars-group">
971
- <h4 class="css-vars-group-title">Other</h4>
972
- ${vars.map(([name, val]) => html`
973
- <div class="css-var-row">
974
- <span class="css-var-name">${name}</span>
975
- <sp-textfield
976
- size="s"
977
- .value=${String(val)}
978
- @change=${(e) => updateVar(name, e.target.value)}
979
- style="flex:1"
980
- ></sp-textfield>
981
- <sp-action-button quiet size="s" @click=${() => deleteVar(name)}>
982
- <sp-icon-delete slot="icon"></sp-icon-delete>
983
- </sp-action-button>
984
- </div>
985
- ${mediaNames.length > 0 ? renderMediaOverrides(name, rootStyle, mediaNames) : nothing}
986
- `)}
987
- ${renderAddRow("--", "Custom Var", "value", addVar)}
988
- </div>
989
- `;
990
- }
991
- function renderMediaOverrides(varName, rootStyle, mediaNames) {
992
- const overrides = [];
993
- for (const mediaName of mediaNames) {
994
- const mediaKey = `@${mediaName}`;
995
- const mediaBlock = rootStyle[mediaKey];
996
- if (mediaBlock && typeof mediaBlock === "object" && mediaBlock[varName]) {
997
- overrides.push({ mediaName, value: mediaBlock[varName] });
998
- }
999
- }
1000
- if (overrides.length === 0) {
1001
- return nothing;
1002
- }
1003
- return html`
1004
- <div class="css-var-media-overrides">
1005
- ${overrides.map((o) => html`
1006
- <div class="css-var-media-row">
1007
- <span class="css-var-media-label">@${o.mediaName}</span>
1008
- <sp-textfield
1009
- size="s"
1010
- .value=${String(o.value)}
1011
- @change=${(e) => {
1012
- if (!rootStyle[`@${o.mediaName}`]) {
1013
- rootStyle[`@${o.mediaName}`] = {};
1014
- }
1015
- rootStyle[`@${o.mediaName}`][varName] = e.target.value;
1016
- updateSiteConfig({ style: { ...rootStyle } });
1017
- }}
1018
- style="max-width:120px"
1019
- ></sp-textfield>
1020
- </div>
1021
- `)}
1022
- </div>
1023
- `;
1024
- }
1025
- function renderAddRow(prefix, placeholder, valuePlaceholder, addVar) {
1026
- let nameEl = null;
1027
- let valEl = null;
1028
- return html`
1029
- <div class="css-var-add-row">
1030
- <sp-textfield
1031
- size="s"
1032
- placeholder=${placeholder}
1033
- ${ref((el) => {
1034
- if (el) {
1035
- nameEl = el;
1036
- }
1037
- })}
1038
- ></sp-textfield>
1039
- <sp-textfield
1040
- size="s"
1041
- placeholder=${valuePlaceholder}
1042
- ${ref((el) => {
1043
- if (el) {
1044
- valEl = el;
1045
- }
1046
- })}
1047
- ></sp-textfield>
1048
- <sp-action-button
1049
- size="s"
1050
- @click=${() => {
1051
- if (nameEl && valEl) {
1052
- addVar(prefix, nameEl.value, valEl.value);
1053
- }
1054
- }}
1055
- >Add</sp-action-button
1056
- >
1057
- </div>
1058
- `;
1059
- }
1060
-
1061
- // src/utils/google-fonts.ts
1062
- var GFONTS_CSS_PREFIX = "https://fonts.googleapis.com/css2?";
1063
- var GFONTS_PRECONNECT_ORIGINS = [
1064
- "https://fonts.googleapis.com",
1065
- "https://fonts.gstatic.com"
1066
- ];
1067
- function isGoogleFontEntry(entry) {
1068
- return entry?.tagName === "link" && entry?.attributes?.rel === "stylesheet" && typeof entry?.attributes?.href === "string" && entry.attributes.href.startsWith(GFONTS_CSS_PREFIX);
1069
- }
1070
- function isGoogleFontPreconnect(entry) {
1071
- return entry?.tagName === "link" && entry?.attributes?.rel === "preconnect" && GFONTS_PRECONNECT_ORIGINS.includes(entry?.attributes?.href);
1072
- }
1073
- function extractFontFamily(href) {
1074
- const match = href.match(/family=([^&:]+)/);
1075
- if (!match) {
1076
- return "";
1077
- }
1078
- return decodeURIComponent(match[1].replaceAll("+", " "));
1079
- }
1080
- function buildGoogleFontUrl(family) {
1081
- return `${GFONTS_CSS_PREFIX}family=${encodeURIComponent(family).replaceAll("%20", "+")}&display=swap`;
1082
- }
1083
- function ensureGoogleFontPreconnects(head) {
1084
- for (const origin of GFONTS_PRECONNECT_ORIGINS) {
1085
- const exists = head.some((e) => e?.tagName === "link" && e?.attributes?.rel === "preconnect" && e?.attributes?.href === origin);
1086
- if (!exists) {
1087
- const attrs = {
1088
- href: origin,
1089
- rel: "preconnect"
1090
- };
1091
- if (origin === "https://fonts.gstatic.com") {
1092
- attrs.crossorigin = "";
1093
- }
1094
- head.push({ attributes: attrs, tagName: "link" });
1095
- }
1096
- }
1097
- }
1098
- function cleanupGoogleFontPreconnects(head) {
1099
- const hasFont = head.some((e) => isGoogleFontEntry(e));
1100
- if (!hasFont) {
1101
- return head.filter((e) => !isGoogleFontPreconnect(e));
1102
- }
1103
- return head;
1104
- }
1105
-
1106
- // src/settings/head-editor.ts
1107
- function renderHeadEditor(container) {
1108
- const config = projectState?.projectConfig || {};
1109
- const headEntries = config.$head || [];
1110
- const save = () => {
1111
- updateSiteConfig({ $head: headEntries });
1112
- };
1113
- const addEntry = (tag) => {
1114
- const attrs = {};
1115
- const entry = { attributes: attrs, tagName: tag };
1116
- if (tag === "link") {
1117
- attrs.rel = "stylesheet";
1118
- attrs.href = "";
1119
- } else if (tag === "meta") {
1120
- attrs.name = "";
1121
- attrs.content = "";
1122
- } else if (tag === "script") {
1123
- attrs.src = "";
1124
- } else if (tag === "style") {
1125
- entry.textContent = "";
1126
- }
1127
- headEntries.push(entry);
1128
- save();
1129
- renderHeadEditor(container);
1130
- };
1131
- const removeEntry = (idx) => {
1132
- headEntries.splice(idx, 1);
1133
- save();
1134
- renderHeadEditor(container);
1135
- };
1136
- const updateEntry = (idx, key, val) => {
1137
- const entry = headEntries[idx];
1138
- if (key === "content" && (entry.tagName === "script" || entry.tagName === "style")) {
1139
- entry.textContent = val;
1140
- } else {
1141
- if (!entry.attributes) {
1142
- entry.attributes = {};
1143
- }
1144
- entry.attributes[key] = val;
1145
- }
1146
- save();
1147
- };
1148
- const tpl = html`
1149
- <div class="settings-section">
1150
- <h3 class="settings-section-title">Google Fonts</h3>
1151
- <p class="settings-field-desc">
1152
- Manage Google Fonts imported across all pages in this project.
1153
- </p>
1154
- ${renderGoogleFontsSection(headEntries, save, () => renderHeadEditor(container))}
1155
- </div>
1156
-
1157
- <div class="settings-section">
1158
- <h3 class="settings-section-title">Head</h3>
1159
- <p class="settings-field-desc">
1160
- Manage global &lt;head&gt; tags — stylesheets, meta tags, scripts, and inline styles.
1161
- </p>
1162
-
1163
- <div class="head-entries">
1164
- ${headEntries.map((entry, idx) => html`
1165
- <div class="head-entry">
1166
- <div class="head-entry-header">
1167
- <span class="head-entry-tag">&lt;${entry.tagName}&gt;</span>
1168
- <sp-action-button quiet size="s" @click=${() => removeEntry(idx)}>
1169
- <sp-icon-delete slot="icon"></sp-icon-delete>
1170
- </sp-action-button>
1171
- </div>
1172
- <div class="head-entry-fields">${renderEntryFields(entry, idx, updateEntry)}</div>
1173
- </div>
1174
- `)}
1175
- </div>
1176
-
1177
- <div class="head-add-actions" style="margin-top:12px;display:flex;gap:8px">
1178
- <sp-action-button size="s" @click=${() => addEntry("link")}> + Link </sp-action-button>
1179
- <sp-action-button size="s" @click=${() => addEntry("meta")}> + Meta </sp-action-button>
1180
- <sp-action-button size="s" @click=${() => addEntry("script")}> + Script </sp-action-button>
1181
- <sp-action-button size="s" @click=${() => addEntry("style")}> + Style </sp-action-button>
1182
- </div>
1183
- </div>
1184
- `;
1185
- render(tpl, container);
1186
- }
1187
- function renderEntryFields(entry, idx, updateEntry) {
1188
- let debounce;
1189
- const onFieldChange = (key) => (e) => {
1190
- clearTimeout(debounce);
1191
- debounce = setTimeout(() => {
1192
- updateEntry(idx, key, e.target.value);
1193
- }, 300);
1194
- };
1195
- const attrs = entry.attributes || {};
1196
- switch (entry.tagName) {
1197
- case "link": {
1198
- return html`
1199
- <div class="settings-field-row">
1200
- <sp-textfield
1201
- size="s"
1202
- label="rel"
1203
- .value=${attrs.rel || ""}
1204
- @change=${onFieldChange("rel")}
1205
- ></sp-textfield>
1206
- <sp-textfield
1207
- size="s"
1208
- label="href"
1209
- .value=${attrs.href || ""}
1210
- @change=${onFieldChange("href")}
1211
- style="flex:1"
1212
- ></sp-textfield>
1213
- </div>
1214
- `;
1215
- }
1216
- case "meta": {
1217
- return html`
1218
- <div class="settings-field-row">
1219
- <sp-textfield
1220
- size="s"
1221
- label="name"
1222
- .value=${attrs.name || ""}
1223
- @change=${onFieldChange("name")}
1224
- ></sp-textfield>
1225
- <sp-textfield
1226
- size="s"
1227
- label="content"
1228
- .value=${attrs.content || ""}
1229
- @change=${onFieldChange("content")}
1230
- style="flex:1"
1231
- ></sp-textfield>
1232
- </div>
1233
- `;
1234
- }
1235
- case "script": {
1236
- return html`
1237
- <div class="settings-field-row">
1238
- <sp-textfield
1239
- size="s"
1240
- label="src"
1241
- .value=${attrs.src || ""}
1242
- @change=${onFieldChange("src")}
1243
- placeholder="URL or leave empty for inline"
1244
- style="flex:1"
1245
- ></sp-textfield>
1246
- </div>
1247
- ${!attrs.src ? html`
1248
- <div class="head-entry-body">
1249
- <label class="settings-field-label">Script body</label>
1250
- <textarea
1251
- class="head-code-editor"
1252
- .value=${entry.textContent || ""}
1253
- @input=${onFieldChange("content")}
1254
- rows="6"
1255
- spellcheck="false"
1256
- ></textarea>
1257
- </div>
1258
- ` : nothing}
1259
- `;
1260
- }
1261
- case "style": {
1262
- return html`
1263
- <div class="head-entry-body">
1264
- <label class="settings-field-label">Style body</label>
1265
- <textarea
1266
- class="head-code-editor"
1267
- .value=${entry.textContent || ""}
1268
- @input=${onFieldChange("content")}
1269
- rows="8"
1270
- spellcheck="false"
1271
- ></textarea>
1272
- </div>
1273
- `;
1274
- }
1275
- default: {
1276
- return nothing;
1277
- }
1278
- }
1279
- }
1280
- function renderGoogleFontsSection(headEntries, save, rerender) {
1281
- const fontEntries = headEntries.filter((e) => isGoogleFontEntry(e));
1282
- const addFont = (family) => {
1283
- ensureGoogleFontPreconnects(headEntries);
1284
- headEntries.push({
1285
- attributes: { href: buildGoogleFontUrl(family), rel: "stylesheet" },
1286
- tagName: "link"
1287
- });
1288
- save();
1289
- rerender();
1290
- };
1291
- const removeFont = (entry) => {
1292
- const idx = headEntries.indexOf(entry);
1293
- if (idx !== -1) {
1294
- headEntries.splice(idx, 1);
1295
- }
1296
- const cleaned = cleanupGoogleFontPreconnects(headEntries);
1297
- if (cleaned !== headEntries) {
1298
- headEntries.length = 0;
1299
- headEntries.push(...cleaned);
1300
- }
1301
- save();
1302
- rerender();
1303
- };
1304
- return html`
1305
- <div class="head-entries" style="margin-bottom:12px">
1306
- ${fontEntries.length > 0 ? fontEntries.map((entry) => html`
1307
- <div class="head-entry" style="flex-direction:row;align-items:center;gap:8px">
1308
- <span style="flex:1"
1309
- >${extractFontFamily(String(entry.attributes?.href || ""))}</span
1310
- >
1311
- <sp-action-button quiet size="s" @click=${() => removeFont(entry)}>
1312
- <sp-icon-delete slot="icon"></sp-icon-delete>
1313
- </sp-action-button>
1314
- </div>
1315
- `) : html`<p class="settings-field-desc" style="margin:0">No fonts imported.</p>`}
1316
- </div>
1317
- <div style="display:flex;gap:8px;align-items:center">
1318
- <sp-textfield
1319
- size="s"
1320
- placeholder="Font family name…"
1321
- style="flex:1"
1322
- @keydown=${(e) => {
1323
- if (e.key !== "Enter") {
1324
- return;
1325
- }
1326
- const family = e.target.value?.trim();
1327
- if (!family) {
1328
- return;
1329
- }
1330
- e.target.value = "";
1331
- addFont(family);
1332
- }}
1333
- ></sp-textfield>
1334
- <sp-action-button
1335
- size="s"
1336
- @click=${(e) => {
1337
- const input = e.target.closest("div")?.querySelector("sp-textfield");
1338
- const family = input?.value?.trim();
1339
- if (!family) {
1340
- return;
1341
- }
1342
- input.value = "";
1343
- addFont(family);
1344
- }}
1345
- >
1346
- + Add
1347
- </sp-action-button>
1348
- </div>
1349
- `;
1350
- }
1351
-
1352
- // src/settings/general-settings.ts
1353
- function renderGeneralSettings(container) {
1354
- const config = projectState?.projectConfig || {};
1355
- const onFaviconUpload = async () => {
1356
- const input = document.createElement("input");
1357
- input.type = "file";
1358
- input.accept = "image/*,.ico,.svg";
1359
- input.addEventListener("change", async () => {
1360
- const file = input.files?.[0];
1361
- if (!file) {
1362
- return;
1363
- }
1364
- const platform = getPlatform();
1365
- await platform.uploadFile("public/favicon.ico", file);
1366
- await updateSiteConfig({ favicon: "/favicon.ico" });
1367
- renderGeneralSettings(container);
1368
- });
1369
- input.click();
1370
- };
1371
- const onAdapterChange = (e) => {
1372
- updateSiteConfig({
1373
- build: { ...config.build, adapter: e.target.value }
1374
- });
1375
- };
1376
- const onEditGlobalStyles = async () => {
1377
- const { closeSettingsModal } = await import("./settings-modal-gj0hrah4.js");
1378
- closeSettingsModal();
1379
- openFileInTab("project.json");
1380
- };
1381
- const media = config.$media || {};
1382
- const mediaEntries = Object.entries(media);
1383
- const onMediaValueChange = (key) => (e) => {
1384
- const updated = { ...media, [key]: e.target.value };
1385
- updateSiteConfig({ $media: updated });
1386
- };
1387
- const onMediaNameChange = (oldKey) => (e) => {
1388
- const rawName = e.target.value.trim();
1389
- const newKey = rawName.startsWith("--") ? rawName : `--${rawName}`;
1390
- if (newKey === oldKey) {
1391
- return;
1392
- }
1393
- const updated = {};
1394
- for (const [k, v] of Object.entries(media)) {
1395
- updated[k === oldKey ? newKey : k] = v;
1396
- }
1397
- updateSiteConfig({ $media: updated });
1398
- renderGeneralSettings(container);
1399
- };
1400
- const onRemoveBreakpoint = (key) => () => {
1401
- const updated = { ...media };
1402
- delete updated[key];
1403
- updateSiteConfig({ $media: updated });
1404
- renderGeneralSettings(container);
1405
- };
1406
- const onAddBreakpoint = () => {
1407
- const updated = { ...media, "--new": "(max-width: 480px)" };
1408
- updateSiteConfig({ $media: updated });
1409
- renderGeneralSettings(container);
1410
- };
1411
- const currentFavicon = config.favicon;
1412
- const tpl = html`
1413
- <div class="settings-section">
1414
- <h3 class="settings-section-title">General</h3>
1415
-
1416
- <div class="settings-field">
1417
- <label class="settings-field-label">Favicon</label>
1418
- <p class="settings-field-desc">Upload an image to use as the site favicon.</p>
1419
- <div style="display:flex;align-items:center;gap:12px">
1420
- ${currentFavicon ? html`<img
1421
- src=${currentFavicon}
1422
- alt="Current favicon"
1423
- style="width:32px;height:32px;object-fit:contain;border:1px solid var(--border);border-radius:var(--radius);padding:2px"
1424
- />` : html`<div
1425
- style="width:32px;height:32px;border:1px dashed var(--border);border-radius:var(--radius);display:flex;align-items:center;justify-content:center;color:var(--fg-dim);font-size:var(--spectrum-font-size-50, 11px)"
1426
- >
1427
- —
1428
- </div>`}
1429
- <sp-action-button size="s" @click=${onFaviconUpload}> Upload Favicon </sp-action-button>
1430
- ${currentFavicon ? html`<span style="font-size:var(--spectrum-font-size-50, 11px);color:var(--fg-dim)"
1431
- >${currentFavicon}</span
1432
- >` : nothing}
1433
- </div>
1434
- </div>
1435
-
1436
- <div class="settings-field">
1437
- <label class="settings-field-label">Platform Adapter</label>
1438
- <p class="settings-field-desc">Build adapter for deployment target.</p>
1439
- <sp-picker
1440
- size="s"
1441
- label="Platform Adapter"
1442
- .value=${config.build?.adapter || "static"}
1443
- @change=${onAdapterChange}
1444
- >
1445
- <sp-menu-item value="static">Static</sp-menu-item>
1446
- <sp-menu-item value="bun">Bun</sp-menu-item>
1447
- <sp-menu-item value="node">Node</sp-menu-item>
1448
- <sp-menu-item value="cloudflare-workers">Cloudflare Workers</sp-menu-item>
1449
- <sp-menu-item value="cloudflare-pages">Cloudflare Pages</sp-menu-item>
1450
- </sp-picker>
1451
- </div>
1452
-
1453
- <div class="settings-field">
1454
- <label class="settings-field-label">Breakpoints</label>
1455
- <p class="settings-field-desc">
1456
- Responsive breakpoints for canvas panels and media query styles.
1457
- </p>
1458
- <div class="settings-media-list">
1459
- ${mediaEntries.map(([key, value]) => {
1460
- const isBase = key === "--";
1461
- return html`
1462
- <div class="settings-media-row">
1463
- ${isBase ? html`<span class="settings-media-name-fixed">Base</span>` : html`<sp-textfield
1464
- size="s"
1465
- class="settings-media-name"
1466
- .value=${key.replace(/^--/, "")}
1467
- placeholder="name"
1468
- @change=${onMediaNameChange(key)}
1469
- ></sp-textfield>`}
1470
- <sp-textfield
1471
- size="s"
1472
- class="settings-media-value"
1473
- .value=${value}
1474
- placeholder=${isBase ? "1280px" : "(max-width: 768px)"}
1475
- @change=${onMediaValueChange(key)}
1476
- ></sp-textfield>
1477
- ${isBase ? nothing : html`<sp-action-button
1478
- size="s"
1479
- quiet
1480
- title="Remove breakpoint"
1481
- @click=${onRemoveBreakpoint(key)}
1482
- >
1483
- ×
1484
- </sp-action-button>`}
1485
- </div>
1486
- `;
1487
- })}
1488
- </div>
1489
- <sp-action-button size="s" style="margin-top:8px" @click=${onAddBreakpoint}>
1490
- + Add Breakpoint
1491
- </sp-action-button>
1492
- </div>
1493
-
1494
- <div class="settings-field">
1495
- <label class="settings-field-label">Global Styles</label>
1496
- <p class="settings-field-desc">Edit default element styles that apply across all pages.</p>
1497
- <sp-action-button size="s" @click=${onEditGlobalStyles}>
1498
- Edit Global Styles
1499
- </sp-action-button>
1500
- </div>
1501
- </div>
1502
- `;
1503
- render(tpl, container);
1504
- }
1505
-
1506
- // src/settings/dependencies-editor.ts
1507
- var JXSUITE_PREFIX = "@jxsuite/";
1508
- var _container = null;
1509
- var _packages = null;
1510
- var _latest = new Map;
1511
- var _busy = false;
1512
- var _addName = "";
1513
- function latestFor(p) {
1514
- if (p.name.startsWith(JXSUITE_PREFIX) && isComparable(VERSION) && isUpgrade(p.version, VERSION)) {
1515
- return VERSION;
1516
- }
1517
- const registry = _latest.get(p.name);
1518
- return registry && isUpgrade(p.version, registry) ? registry : null;
1519
- }
1520
- async function load() {
1521
- const platform = getPlatform();
1522
- try {
1523
- _packages = await platform.listPackages();
1524
- } catch {
1525
- _packages = [];
1526
- }
1527
- _latest = new Map;
1528
- if (platform.outdatedPackages) {
1529
- try {
1530
- for (const o of await platform.outdatedPackages()) {
1531
- _latest.set(o.name, o.latest);
1532
- }
1533
- } catch {}
1534
- }
1535
- render2();
1536
- }
1537
- async function withBusy(fn) {
1538
- if (_busy) {
1539
- return;
1540
- }
1541
- _busy = true;
1542
- render2();
1543
- const progress = showProgressModal({ status: "Running bun…", title: "Updating dependencies" });
1544
- try {
1545
- await fn();
1546
- progress.done();
1547
- } catch (error) {
1548
- progress.fail(error instanceof Error ? error.message : String(error));
1549
- } finally {
1550
- _busy = false;
1551
- await load();
1552
- }
1553
- }
1554
- async function onAdd() {
1555
- const name = _addName.trim();
1556
- if (!name) {
1557
- return;
1558
- }
1559
- await withBusy(async () => {
1560
- await getPlatform().addPackage(name);
1561
- _addName = "";
1562
- statusMessage(`Added ${name}`);
1563
- });
1564
- }
1565
- async function onRemove(p) {
1566
- await withBusy(async () => {
1567
- await getPlatform().removePackage(p.name);
1568
- statusMessage(`Removed ${p.name}`);
1569
- });
1570
- }
1571
- async function onUpdate(p, latest) {
1572
- const platform = getPlatform();
1573
- if (!platform.setPackageVersions) {
1574
- return;
1575
- }
1576
- await withBusy(async () => {
1577
- const target = stripRange(latest);
1578
- const res = await platform.setPackageVersions([
1579
- { dev: Boolean(p.dev), name: p.name, version: `^${target}` }
1580
- ]);
1581
- if (!res.ok) {
1582
- throw new Error(res.log ?? "Update failed");
1583
- }
1584
- statusMessage(`Updated ${p.name} to ${target}`);
1585
- });
1586
- }
1587
- async function onUpdateAll() {
1588
- const platform = getPlatform();
1589
- if (!platform.setPackageVersions) {
1590
- return;
1591
- }
1592
- const updates = (_packages ?? []).map((p) => {
1593
- const latest = latestFor(p);
1594
- return latest ? { dev: Boolean(p.dev), name: p.name, version: `^${stripRange(latest)}` } : null;
1595
- }).filter((u) => u !== null);
1596
- if (updates.length === 0) {
1597
- return;
1598
- }
1599
- await withBusy(async () => {
1600
- const res = await platform.setPackageVersions(updates);
1601
- if (!res.ok) {
1602
- throw new Error(res.log ?? "Update failed");
1603
- }
1604
- statusMessage(`Updated ${updates.length} package(s)`);
1605
- });
1606
- }
1607
- async function onReinstall() {
1608
- const platform = getPlatform();
1609
- if (!platform.installDependencies) {
1610
- return;
1611
- }
1612
- await withBusy(async () => {
1613
- const res = await platform.installDependencies();
1614
- if (!res.ok) {
1615
- throw new Error(res.log ?? "Install failed");
1616
- }
1617
- statusMessage("Dependencies reinstalled");
1618
- });
1619
- }
1620
- function row(p) {
1621
- const latest = latestFor(p);
1622
- return html`
1623
- <sp-table-row>
1624
- <sp-table-cell>
1625
- ${p.name}${p.dev ? html`<span style="color:var(--fg-dim);font-size:10px"> · dev</span>` : ""}
1626
- </sp-table-cell>
1627
- <sp-table-cell>${p.version}</sp-table-cell>
1628
- <sp-table-cell>${latest ?? "—"}</sp-table-cell>
1629
- <sp-table-cell>
1630
- ${latest ? html`<sp-action-button
1631
- size="s"
1632
- quiet
1633
- ?disabled=${_busy}
1634
- title="Update to ${latest}"
1635
- @click=${() => onUpdate(p, latest)}
1636
- >
1637
- <sp-icon-refresh slot="icon"></sp-icon-refresh>
1638
- </sp-action-button>` : ""}
1639
- <sp-action-button
1640
- size="s"
1641
- quiet
1642
- ?disabled=${_busy}
1643
- title="Remove"
1644
- @click=${() => onRemove(p)}
1645
- >
1646
- <sp-icon-delete slot="icon"></sp-icon-delete>
1647
- </sp-action-button>
1648
- </sp-table-cell>
1649
- </sp-table-row>
1650
- `;
1651
- }
1652
- function render2() {
1653
- if (!_container) {
1654
- return;
1655
- }
1656
- const pkgs = _packages ?? [];
1657
- const hasUpdates = pkgs.some((p) => latestFor(p) !== null);
1658
- const tpl = html`
1659
- <div class="settings-section">
1660
- <h3 class="settings-section-title">Dependencies</h3>
1661
- <p class="settings-field-desc">Manage this project's npm dependencies.</p>
1662
-
1663
- <div style="display:flex;gap:8px;margin-bottom:12px;align-items:center">
1664
- <sp-textfield
1665
- size="s"
1666
- placeholder="package-name"
1667
- .value=${_addName}
1668
- ?disabled=${_busy}
1669
- @input=${(e) => {
1670
- _addName = e.target.value;
1671
- }}
1672
- ></sp-textfield>
1673
- <sp-action-button size="s" ?disabled=${_busy} @click=${onAdd}>
1674
- <sp-icon-add slot="icon"></sp-icon-add>
1675
- Add
1676
- </sp-action-button>
1677
- <span style="flex:1"></span>
1678
- ${hasUpdates ? html`<sp-action-button size="s" ?disabled=${_busy} @click=${onUpdateAll}>
1679
- Update all
1680
- </sp-action-button>` : ""}
1681
- <sp-action-button
1682
- size="s"
1683
- quiet
1684
- ?disabled=${_busy}
1685
- title="Reinstall (bun install)"
1686
- @click=${onReinstall}
1687
- >
1688
- <sp-icon-refresh slot="icon"></sp-icon-refresh>
1689
- Reinstall
1690
- </sp-action-button>
1691
- </div>
1692
-
1693
- ${_packages === null ? html`<p class="about-muted">Loading…</p>` : pkgs.length === 0 ? html`<p class="about-muted">No dependencies.</p>` : html`
1694
- <sp-table size="s">
1695
- <sp-table-head>
1696
- <sp-table-head-cell>Package</sp-table-head-cell>
1697
- <sp-table-head-cell>Current</sp-table-head-cell>
1698
- <sp-table-head-cell>Latest</sp-table-head-cell>
1699
- <sp-table-head-cell></sp-table-head-cell>
1700
- </sp-table-head>
1701
- <sp-table-body> ${pkgs.map((p) => row(p))} </sp-table-body>
1702
- </sp-table>
1703
- `}
1704
- </div>
1705
- `;
1706
- render(tpl, _container);
1707
- }
1708
- function renderDependenciesEditor(container) {
1709
- _container = container;
1710
- _packages = null;
1711
- _addName = "";
1712
- render2();
1713
- load();
1714
- }
1715
-
1716
- // src/settings/settings-modal.ts
1717
- var sectionRegistry = new Map;
1718
- function registerSettingsSection(section) {
1719
- sectionRegistry.set(section.key, section);
1720
- }
1721
- function unregisterSettingsSection(key) {
1722
- sectionRegistry.delete(key);
1723
- if (_activeSection === key) {
1724
- _activeSection = "general";
1725
- }
1726
- }
1727
- function sortedSections() {
1728
- return [...sectionRegistry.values()].toSorted((a, b) => a.order - b.order);
1729
- }
1730
- registerSettingsSection({
1731
- icon: "sp-icon-properties",
1732
- key: "general",
1733
- label: "General",
1734
- order: 10,
1735
- render: renderGeneralSettings
1736
- });
1737
- registerSettingsSection({
1738
- icon: "sp-icon-file-single-web-page",
1739
- key: "head",
1740
- label: "Head",
1741
- order: 20,
1742
- render: renderHeadEditor
1743
- });
1744
- registerSettingsSection({
1745
- icon: "sp-icon-brush",
1746
- key: "cssVars",
1747
- label: "CSS Variables",
1748
- order: 30,
1749
- render: renderCssVarsEditor
1750
- });
1751
- registerSettingsSection({
1752
- icon: "sp-icon-data",
1753
- key: "definitions",
1754
- label: "Definitions",
1755
- order: 40,
1756
- render: renderDefsEditor
1757
- });
1758
- registerSettingsSection({
1759
- icon: "sp-icon-box",
1760
- key: "dependencies",
1761
- label: "Dependencies",
1762
- order: 60,
1763
- render: renderDependenciesEditor
1764
- });
1765
- var _handle = null;
1766
- var _activeSection = "general";
1767
- var _contentEl = null;
1768
- function openSettingsModal(section) {
1769
- if (_handle) {
1770
- return;
1771
- }
1772
- _activeSection = section ?? "general";
1773
- renderModal();
1774
- import("./extension-sections-qct0gt8f.js").then(async ({ syncExtensionSettingsSections }) => {
1775
- await syncExtensionSettingsSections();
1776
- if (_handle) {
1777
- renderModal();
1778
- renderActiveSection();
1779
- }
1780
- }).catch(() => {});
1781
- }
1782
- function closeSettingsModal() {
1783
- if (!_handle) {
1784
- return;
1785
- }
1786
- _handle.close();
1787
- _handle = null;
1788
- _contentEl = null;
1789
- }
1790
- function renderModal() {
1791
- const onNavClick = (key) => {
1792
- _activeSection = key;
1793
- renderModal();
1794
- renderActiveSection();
1795
- };
1796
- const tpl = html`
1797
- <sp-underlay open @close=${closeSettingsModal}></sp-underlay>
1798
- <div
1799
- class="settings-modal"
1800
- @keydown=${(e) => {
1801
- if (e.key === "Escape") {
1802
- closeSettingsModal();
1803
- }
1804
- }}
1805
- >
1806
- <div class="settings-modal-header">
1807
- <h2 class="settings-modal-title">Settings</h2>
1808
- <sp-action-button quiet size="s" @click=${closeSettingsModal} title="Close">
1809
- <sp-icon-close slot="icon"></sp-icon-close>
1810
- </sp-action-button>
1811
- </div>
1812
- <div class="settings-modal-body">
1813
- <nav class="settings-modal-nav">
1814
- ${sortedSections().map((s) => html`
1815
- <button
1816
- class=${classMap({
1817
- active: _activeSection === s.key,
1818
- "settings-nav-item": true
1819
- })}
1820
- @click=${() => onNavClick(s.key)}
1821
- >
1822
- ${s.label}
1823
- </button>
1824
- `)}
1825
- </nav>
1826
- <div
1827
- class="settings-modal-content"
1828
- ${ref((el) => {
1829
- _contentEl = el || null;
1830
- if (_contentEl) {
1831
- requestAnimationFrame(() => renderActiveSection());
1832
- }
1833
- })}
1834
- ></div>
1835
- </div>
1836
- </div>
1837
- `;
1838
- if (!_handle) {
1839
- _handle = openModal(tpl);
1840
- } else {
1841
- _handle.update(tpl);
1842
- }
1843
- }
1844
- function renderActiveSection() {
1845
- if (!_handle || !_contentEl) {
1846
- return;
1847
- }
1848
- sectionRegistry.get(_activeSection)?.render(_contentEl);
1849
- }
1850
-
1851
- export { detectFieldFormat, fieldCardTpl, addFieldFormTpl, schemaForType, yamlDefault, isSchemeQuery, schemeOfQuery, parseMediaEntries, isGoogleFontEntry, isGoogleFontPreconnect, registerSettingsSection, unregisterSettingsSection, openSettingsModal, closeSettingsModal };
1852
-
1853
- //# debugId=8B96522C815A708964756E2164756E21
1854
- //# sourceMappingURL=studio-j6gqyjf4.js.map