@backmatter/studio 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. package/dist/chunks/UiKitPage-CgNMOqfE.js +172 -0
  2. package/dist/chunks/WorkspaceRoutes-DgRtdie8.js +87297 -0
  3. package/dist/chunks/abap-Y8Dl9g_6.js +6 -0
  4. package/dist/chunks/actionscript-3-DQVEcJUW.js +6 -0
  5. package/dist/chunks/ada-vP6ak0IW.js +6 -0
  6. package/dist/chunks/andromeeda-BbmzSJq1.js +4 -0
  7. package/dist/chunks/angular-html-DPB4Rf0C.js +32 -0
  8. package/dist/chunks/angular-ts-CTOR2ofC.js +21 -0
  9. package/dist/chunks/apache-BUjz-sD2.js +6 -0
  10. package/dist/chunks/apex-OyTfjCYK.js +6 -0
  11. package/dist/chunks/apl-CjNiDgad.js +16 -0
  12. package/dist/chunks/applescript-BPx7YFFu.js +6 -0
  13. package/dist/chunks/ara-Z2fSOxSw.js +6 -0
  14. package/dist/chunks/asciidoc-C1T9ziH6.js +6 -0
  15. package/dist/chunks/asm-BTWLY5ym.js +6 -0
  16. package/dist/chunks/astro-CFFExE8Q.js +18 -0
  17. package/dist/chunks/aurora-x-BwoVEUWZ.js +4 -0
  18. package/dist/chunks/awk-Fb0P9dkn.js +6 -0
  19. package/dist/chunks/ayu-dark-DJoqd4M9.js +4 -0
  20. package/dist/chunks/ayu-light-BzXEJRJ-.js +4 -0
  21. package/dist/chunks/ayu-mirage-BJ2oZGzi.js +4 -0
  22. package/dist/chunks/ballerina-oZK-YekG.js +6 -0
  23. package/dist/chunks/bat-0FvbqU9S.js +6 -0
  24. package/dist/chunks/beancount-DqJEb89h.js +6 -0
  25. package/dist/chunks/berry-DODBq_Ff.js +6 -0
  26. package/dist/chunks/bibtex-EULQRLY5.js +6 -0
  27. package/dist/chunks/bicep-BorU73w0.js +6 -0
  28. package/dist/chunks/bird2-CIjBSNj3.js +6 -0
  29. package/dist/chunks/blade-D0HyNvCw.js +20 -0
  30. package/dist/chunks/bsl-NkNNwerW.js +8 -0
  31. package/dist/chunks/c-eeMepfLm.js +6 -0
  32. package/dist/chunks/c3-BY5XW5ym.js +6 -0
  33. package/dist/chunks/cadence-02UX7mW8.js +6 -0
  34. package/dist/chunks/cairo-DM6WF2e3.js +8 -0
  35. package/dist/chunks/catppuccin-frappe-D3cH2rXe.js +4 -0
  36. package/dist/chunks/catppuccin-latte-C0LRGUW4.js +4 -0
  37. package/dist/chunks/catppuccin-macchiato-c5wQ11TT.js +4 -0
  38. package/dist/chunks/catppuccin-mocha-WMD6Qvya.js +4 -0
  39. package/dist/chunks/clarity-PKm5CwqM.js +6 -0
  40. package/dist/chunks/clojure-CXJfHrL3.js +6 -0
  41. package/dist/chunks/cmake-BJz8BOTU.js +6 -0
  42. package/dist/chunks/cobol-HihOMwht.js +10 -0
  43. package/dist/chunks/codeowners-Bt9yU6NX.js +6 -0
  44. package/dist/chunks/codeql-DHkodjjI.js +6 -0
  45. package/dist/chunks/coffee-DGBR_nr_.js +8 -0
  46. package/dist/chunks/common-lisp-EVqT9Zhp.js +6 -0
  47. package/dist/chunks/coq-B0L9upzn.js +6 -0
  48. package/dist/chunks/cpp-Cj177cuW.js +18 -0
  49. package/dist/chunks/crystal-CRJyc4G-.js +18 -0
  50. package/dist/chunks/csharp-CCgA4A09.js +6 -0
  51. package/dist/chunks/css-CECN5uSL.js +6 -0
  52. package/dist/chunks/csv-CmYOceLb.js +6 -0
  53. package/dist/chunks/cue-ZzumE7IT.js +6 -0
  54. package/dist/chunks/cypher-jpdmjtA6.js +6 -0
  55. package/dist/chunks/d-CBagWSwH.js +6 -0
  56. package/dist/chunks/dark-plus-pUHDTVV0.js +4 -0
  57. package/dist/chunks/dart-6ObCrKr9.js +6 -0
  58. package/dist/chunks/dashboard-XKKZuJGm.js +1736 -0
  59. package/dist/chunks/dax-CcDT-8dH.js +6 -0
  60. package/dist/chunks/define-studio-BYtYDGLX.js +33 -0
  61. package/dist/chunks/desktop-B93p9R9O.js +6 -0
  62. package/dist/chunks/diff-BxzP2J8R.js +6 -0
  63. package/dist/chunks/docker-CsHqm9tx.js +6 -0
  64. package/dist/chunks/dotenv-BMjVjUL1.js +6 -0
  65. package/dist/chunks/dracula-BtZx2Kac.js +4 -0
  66. package/dist/chunks/dracula-soft-BKa-aqBv.js +4 -0
  67. package/dist/chunks/dream-maker-PAx17jaB.js +6 -0
  68. package/dist/chunks/edge-BYQkOzbF.js +12 -0
  69. package/dist/chunks/elixir-Dh036GMp.js +8 -0
  70. package/dist/chunks/elm-BtNbw_Cd.js +8 -0
  71. package/dist/chunks/emacs-lisp-Cfxdx5D-.js +6 -0
  72. package/dist/chunks/erb-ScVOXVpH.js +10 -0
  73. package/dist/chunks/erlang-DNcDT8Hi.js +8 -0
  74. package/dist/chunks/everforest-dark-DMCBqXCK.js +4 -0
  75. package/dist/chunks/everforest-light-BbXl82Em.js +4 -0
  76. package/dist/chunks/fennel-N4WcXuKx.js +6 -0
  77. package/dist/chunks/fish-BTDEUgqH.js +6 -0
  78. package/dist/chunks/fluent-BMXUxfv1.js +6 -0
  79. package/dist/chunks/fortran-fixed-form-B67KFkXH.js +8 -0
  80. package/dist/chunks/fortran-free-form-CwqYvCLJ.js +6 -0
  81. package/dist/chunks/fsharp-CYOiIVNx.js +8 -0
  82. package/dist/chunks/gdresource-CvCIUjhi.js +10 -0
  83. package/dist/chunks/gdscript-DSAxJ_aS.js +6 -0
  84. package/dist/chunks/gdshader-Bk8fF6yr.js +6 -0
  85. package/dist/chunks/genie-DzUvd7U9.js +6 -0
  86. package/dist/chunks/gherkin-DHRaV0YP.js +6 -0
  87. package/dist/chunks/git-commit-Bd32YZ0K.js +8 -0
  88. package/dist/chunks/git-rebase-ZWUFO_T4.js +8 -0
  89. package/dist/chunks/github-dark-DenFmJkN.js +4 -0
  90. package/dist/chunks/github-dark-default-BJPUVz4H.js +4 -0
  91. package/dist/chunks/github-dark-dimmed-DUshB20C.js +4 -0
  92. package/dist/chunks/github-dark-high-contrast-D3aGCnF8.js +4 -0
  93. package/dist/chunks/github-light-JYsPkUQd.js +4 -0
  94. package/dist/chunks/github-light-default-D99KPAby.js +4 -0
  95. package/dist/chunks/github-light-high-contrast-BbmZE-Mp.js +4 -0
  96. package/dist/chunks/gleam-Bv284lvN.js +6 -0
  97. package/dist/chunks/glimmer-js-DkxNrfPT.js +14 -0
  98. package/dist/chunks/glimmer-ts-D6YZEmK_.js +14 -0
  99. package/dist/chunks/glsl-CkUcVZNK.js +8 -0
  100. package/dist/chunks/gn-XtJxiLa4.js +6 -0
  101. package/dist/chunks/gnuplot-yPG9-sE_.js +6 -0
  102. package/dist/chunks/go-CvFNMTvu.js +6 -0
  103. package/dist/chunks/graphql-CBu2ehBn.js +14 -0
  104. package/dist/chunks/groovy-CJQTphOW.js +6 -0
  105. package/dist/chunks/gruvbox-dark-hard-C5HOtKIh.js +4 -0
  106. package/dist/chunks/gruvbox-dark-medium-FVgwJHuz.js +4 -0
  107. package/dist/chunks/gruvbox-dark-soft-B46F314v.js +4 -0
  108. package/dist/chunks/gruvbox-light-hard-CJD38wDZ.js +4 -0
  109. package/dist/chunks/gruvbox-light-medium-BlIhMYTA.js +4 -0
  110. package/dist/chunks/gruvbox-light-soft-DoPHyLVZ.js +4 -0
  111. package/dist/chunks/hack-ItRNKiEb.js +10 -0
  112. package/dist/chunks/haml-NZLVzu_R.js +10 -0
  113. package/dist/chunks/handlebars-mxStpSE7.js +14 -0
  114. package/dist/chunks/haskell-WeIwNIP6.js +6 -0
  115. package/dist/chunks/haxe-TztHsm5T.js +6 -0
  116. package/dist/chunks/hcl-D438OF-I.js +6 -0
  117. package/dist/chunks/hjson-DYBUbqOl.js +6 -0
  118. package/dist/chunks/hlsl-Bk8TCZNL.js +6 -0
  119. package/dist/chunks/horizon-CJQ10nlf.js +4 -0
  120. package/dist/chunks/horizon-bright-CdkBZOMB.js +4 -0
  121. package/dist/chunks/houston-BDYrDoDW.js +4 -0
  122. package/dist/chunks/html-B50bmoVb.js +10 -0
  123. package/dist/chunks/html-derivative-C6bxFbFW.js +8 -0
  124. package/dist/chunks/http-DLvAkeD-.js +14 -0
  125. package/dist/chunks/hurl-CgkFN90t.js +12 -0
  126. package/dist/chunks/hxml-GbqSQCLa.js +8 -0
  127. package/dist/chunks/hy-Brt5EZ7-.js +6 -0
  128. package/dist/chunks/imba-CimUv-Uh.js +6 -0
  129. package/dist/chunks/index-CFAIR8GH.js +18924 -0
  130. package/dist/chunks/ini-BZIuRIvJ.js +6 -0
  131. package/dist/chunks/java-DY6VlHhP.js +6 -0
  132. package/dist/chunks/javascript-C25yR2R2.js +6 -0
  133. package/dist/chunks/jinja-CFW5uAwY.js +11 -0
  134. package/dist/chunks/jison-DdreslRX.js +8 -0
  135. package/dist/chunks/json-DxJze_jm.js +6 -0
  136. package/dist/chunks/json5-BT4Fjg39.js +6 -0
  137. package/dist/chunks/jsonc-CHjZD8gR.js +6 -0
  138. package/dist/chunks/jsonl-BGuvDmy9.js +6 -0
  139. package/dist/chunks/jsonnet-Bx2cfsXg.js +6 -0
  140. package/dist/chunks/jssm-BcADi6EI.js +6 -0
  141. package/dist/chunks/jsx-BtKADgXT.js +6 -0
  142. package/dist/chunks/julia-CZiKXNNP.js +16 -0
  143. package/dist/chunks/just-CEK2SJ_k.js +18 -0
  144. package/dist/chunks/kanagawa-dragon-CiKur4Hl.js +4 -0
  145. package/dist/chunks/kanagawa-lotus-BKu-smKu.js +4 -0
  146. package/dist/chunks/kanagawa-wave-CQwozSzG.js +4 -0
  147. package/dist/chunks/kdl-BNOv9TC3.js +6 -0
  148. package/dist/chunks/kotlin-ByBMgTeR.js +6 -0
  149. package/dist/chunks/kusto-DH_XitHS.js +6 -0
  150. package/dist/chunks/laserwave-6a00oqik.js +4 -0
  151. package/dist/chunks/latex-B8Egmqc5.js +8 -0
  152. package/dist/chunks/lean-BnVxaZxY.js +6 -0
  153. package/dist/chunks/less-B1GLI2Di.js +6 -0
  154. package/dist/chunks/light-plus-CZuVqSLX.js +4 -0
  155. package/dist/chunks/liquid-CHzkx3jT.js +14 -0
  156. package/dist/chunks/llvm-Bk2XctFf.js +6 -0
  157. package/dist/chunks/log-Al8wyEFV.js +6 -0
  158. package/dist/chunks/logo-DBa4JDzV.js +6 -0
  159. package/dist/chunks/lua-Bp3IRv7I.js +8 -0
  160. package/dist/chunks/luau-UQyhudEE.js +6 -0
  161. package/dist/chunks/make-CsMclxtr.js +6 -0
  162. package/dist/chunks/markdown-CrScaQ96.js +6 -0
  163. package/dist/chunks/marko-CJBA24Ri.js +14 -0
  164. package/dist/chunks/material-theme-D6KBX41T.js +4 -0
  165. package/dist/chunks/material-theme-darker-CkRroheE.js +4 -0
  166. package/dist/chunks/material-theme-lighter-BUBw43Yz.js +4 -0
  167. package/dist/chunks/material-theme-ocean-ClGX14Ja.js +4 -0
  168. package/dist/chunks/material-theme-palenight-C1RVm8K1.js +4 -0
  169. package/dist/chunks/matlab-BOAaUVP0.js +6 -0
  170. package/dist/chunks/mdc-C9YSUwVC.js +12 -0
  171. package/dist/chunks/mdx-BOhZZUJ8.js +6 -0
  172. package/dist/chunks/mermaid-C3rz4dYh.js +6 -0
  173. package/dist/chunks/min-dark-C7ak0t6c.js +4 -0
  174. package/dist/chunks/min-light-CKFxVcPp.js +4 -0
  175. package/dist/chunks/mipsasm-CTx18fBl.js +6 -0
  176. package/dist/chunks/mojo-EIZIZRTQ.js +6 -0
  177. package/dist/chunks/monokai-C1KBYcO0.js +4 -0
  178. package/dist/chunks/moonbit-B1TV0fG3.js +6 -0
  179. package/dist/chunks/move-Db4ltDq1.js +6 -0
  180. package/dist/chunks/narrat-DmhDCBs-.js +6 -0
  181. package/dist/chunks/nextflow-47kAzSl1.js +8 -0
  182. package/dist/chunks/nextflow-groovy-Drz_2V0j.js +6 -0
  183. package/dist/chunks/nginx-D7O4WoB1.js +8 -0
  184. package/dist/chunks/night-owl-Bm2rzalh.js +4 -0
  185. package/dist/chunks/night-owl-light-CBI5u5kw.js +4 -0
  186. package/dist/chunks/nim-QAjRdh9w.js +20 -0
  187. package/dist/chunks/nix-fTRXMGic.js +9 -0
  188. package/dist/chunks/nord-CC5OiUXg.js +4 -0
  189. package/dist/chunks/nushell-BGCPRlV5.js +6 -0
  190. package/dist/chunks/objective-c-Itk8tzmv.js +6 -0
  191. package/dist/chunks/objective-cpp-DGt5UKRO.js +6 -0
  192. package/dist/chunks/ocaml-eSVK32Eg.js +6 -0
  193. package/dist/chunks/odin-BItnF517.js +6 -0
  194. package/dist/chunks/one-dark-pro-DTA3VF0_.js +4 -0
  195. package/dist/chunks/one-light-LkMrt1Cf.js +4 -0
  196. package/dist/chunks/openscad-Sp5uZ6f2.js +6 -0
  197. package/dist/chunks/pascal-xy8pJNns.js +6 -0
  198. package/dist/chunks/perl-DkVrgJBg.js +16 -0
  199. package/dist/chunks/php-BIzsF_5x.js +18 -0
  200. package/dist/chunks/pkl-C-zSNmaA.js +6 -0
  201. package/dist/chunks/plastic-CSTz3KZp.js +4 -0
  202. package/dist/chunks/plsql-pVbGZfOv.js +6 -0
  203. package/dist/chunks/po-BNfHvqmm.js +6 -0
  204. package/dist/chunks/poimandres-C-VADXHD.js +4 -0
  205. package/dist/chunks/polar-CAZahv3u.js +6 -0
  206. package/dist/chunks/postcss-05aHdL-n.js +6 -0
  207. package/dist/chunks/powerquery-DI9HkTvs.js +6 -0
  208. package/dist/chunks/powershell-Clc4ydu-.js +6 -0
  209. package/dist/chunks/prisma-FZjmVtSl.js +6 -0
  210. package/dist/chunks/prolog-C5-yg4TO.js +6 -0
  211. package/dist/chunks/proto-C7QgialS.js +6 -0
  212. package/dist/chunks/pug-XOw9Q1Ho.js +12 -0
  213. package/dist/chunks/puppet-CUJHmnxV.js +6 -0
  214. package/dist/chunks/purescript-rUfGld-4.js +6 -0
  215. package/dist/chunks/python-BFNSHbwJ.js +6 -0
  216. package/dist/chunks/qml-rTNXsquU.js +8 -0
  217. package/dist/chunks/qmldir-BInDYbpo.js +6 -0
  218. package/dist/chunks/qss-AeJTysr_.js +6 -0
  219. package/dist/chunks/r-CSmzDPi7.js +6 -0
  220. package/dist/chunks/racket-B83wSAja.js +6 -0
  221. package/dist/chunks/raku-nEQ4ZJJ7.js +6 -0
  222. package/dist/chunks/razor-Ci8D0dQK.js +10 -0
  223. package/dist/chunks/red-7y8PH7HH.js +4 -0
  224. package/dist/chunks/reg-m_s_Kiip.js +6 -0
  225. package/dist/chunks/regexp-BazyLpPg.js +6 -0
  226. package/dist/chunks/rel-BcRfyd6Q.js +6 -0
  227. package/dist/chunks/riscv-Ce8MAQLP.js +6 -0
  228. package/dist/chunks/ron-DCEEQypA.js +6 -0
  229. package/dist/chunks/rose-pine-BKc3yVeu.js +4 -0
  230. package/dist/chunks/rose-pine-dawn-BulJcPZT.js +4 -0
  231. package/dist/chunks/rose-pine-moon-j6jiXKV8.js +4 -0
  232. package/dist/chunks/rosmsg-Cz0w1km8.js +6 -0
  233. package/dist/chunks/rst-DM32Wy3O.js +22 -0
  234. package/dist/chunks/ruby-BeqCs27h.js +30 -0
  235. package/dist/chunks/rust-CLzF9zIN.js +6 -0
  236. package/dist/chunks/sas-fpEvgATw.js +8 -0
  237. package/dist/chunks/sass-DxHp5rTx.js +6 -0
  238. package/dist/chunks/scala-D4grkFkl.js +6 -0
  239. package/dist/chunks/scheme-BCRWuEm4.js +6 -0
  240. package/dist/chunks/scss-B1FaCqwR.js +8 -0
  241. package/dist/chunks/sdbl-B7T8abf4.js +6 -0
  242. package/dist/chunks/shaderlab-Cr62-Wb4.js +8 -0
  243. package/dist/chunks/shellscript-InADTalH.js +6 -0
  244. package/dist/chunks/shellsession-DiDJNQdy.js +8 -0
  245. package/dist/chunks/slack-dark-i7wN4OET.js +4 -0
  246. package/dist/chunks/slack-ochin-ndHf0LoP.js +4 -0
  247. package/dist/chunks/smalltalk-BlI1_OkM.js +6 -0
  248. package/dist/chunks/snazzy-light-BlSJXAu4.js +4 -0
  249. package/dist/chunks/solarized-dark-UTmkh7lw.js +4 -0
  250. package/dist/chunks/solarized-light-BheCkDPT.js +4 -0
  251. package/dist/chunks/solidity-DUWnFhS6.js +6 -0
  252. package/dist/chunks/soy-C1-6njHa.js +8 -0
  253. package/dist/chunks/sparql-B0KWFEri.js +8 -0
  254. package/dist/chunks/splunk-CRXR8A9s.js +6 -0
  255. package/dist/chunks/sql-Cn_v3PB0.js +6 -0
  256. package/dist/chunks/ssh-config-DP-hNVbF.js +6 -0
  257. package/dist/chunks/stata-B8c5fTjX.js +8 -0
  258. package/dist/chunks/stylus-CyKEU1Ej.js +6 -0
  259. package/dist/chunks/surrealql-CQi7GQN7.js +8 -0
  260. package/dist/chunks/svelte-rYri41WT.js +14 -0
  261. package/dist/chunks/swift-DJpUqPLg.js +6 -0
  262. package/dist/chunks/synthwave-84-NU3C_KFZ.js +4 -0
  263. package/dist/chunks/system-verilog-BCm7smPJ.js +6 -0
  264. package/dist/chunks/systemd-C-4qm6XH.js +6 -0
  265. package/dist/chunks/talonscript-CFF3LF_O.js +6 -0
  266. package/dist/chunks/tasl-Cg_WBUAe.js +6 -0
  267. package/dist/chunks/tcl-DN7buRTF.js +6 -0
  268. package/dist/chunks/templ-Crs9Ui8q.js +12 -0
  269. package/dist/chunks/terraform-DGvcn9zM.js +6 -0
  270. package/dist/chunks/tex-AHxmLTL0.js +8 -0
  271. package/dist/chunks/tokyo-night-DP4TmcQl.js +4 -0
  272. package/dist/chunks/toml-DY62mUL_.js +6 -0
  273. package/dist/chunks/ts-tags-ioVe2PKw.js +41 -0
  274. package/dist/chunks/tsv-BtvSkaG0.js +6 -0
  275. package/dist/chunks/tsx-B8rCNbgL.js +6 -0
  276. package/dist/chunks/turtle-_H59FV7D.js +6 -0
  277. package/dist/chunks/twig-DwV2Fi4L.js +18 -0
  278. package/dist/chunks/typescript-RycA9KXf.js +6 -0
  279. package/dist/chunks/typespec-DWqp-kUU.js +6 -0
  280. package/dist/chunks/typst-D_1QKWns.js +6 -0
  281. package/dist/chunks/v-BPCNiyYe.js +6 -0
  282. package/dist/chunks/vala-uxaPR7d1.js +6 -0
  283. package/dist/chunks/vb-D8_c5-KN.js +6 -0
  284. package/dist/chunks/verilog-B-bybjPF.js +6 -0
  285. package/dist/chunks/vesper-BckBta1U.js +4 -0
  286. package/dist/chunks/vhdl-CUlNa8ac.js +6 -0
  287. package/dist/chunks/viml-DsfA-sWm.js +6 -0
  288. package/dist/chunks/vitesse-black-BoGvW84i.js +4 -0
  289. package/dist/chunks/vitesse-dark-Cym-eLtO.js +4 -0
  290. package/dist/chunks/vitesse-light-CcmG315c.js +4 -0
  291. package/dist/chunks/vue-DXEmyXn9.js +31 -0
  292. package/dist/chunks/vue-html-j9xNEdu3.js +8 -0
  293. package/dist/chunks/vue-vine-D41-N99t.js +18 -0
  294. package/dist/chunks/vyper-CPQuu50u.js +6 -0
  295. package/dist/chunks/wasm-BBXxrAl7.js +6 -0
  296. package/dist/chunks/wasm-DQxwEHae.js +7 -0
  297. package/dist/chunks/wenyan-pbVjoM9_.js +6 -0
  298. package/dist/chunks/wgsl-DY4iK1q1.js +6 -0
  299. package/dist/chunks/wikitext-Z-MoUasO.js +6 -0
  300. package/dist/chunks/wit-CQMQOlTg.js +6 -0
  301. package/dist/chunks/wolfram-Dz4KXISs.js +6 -0
  302. package/dist/chunks/xml-C2J0sS9M.js +8 -0
  303. package/dist/chunks/xsl-BmSZphgC.js +8 -0
  304. package/dist/chunks/yaml-DaO7k5B1.js +6 -0
  305. package/dist/chunks/zenscript-CxBjpf9c.js +6 -0
  306. package/dist/chunks/zig-Vm0PO9wB.js +6 -0
  307. package/dist/dashboard.js +8 -0
  308. package/dist/define.js +4 -0
  309. package/dist/index.js +317 -0
  310. package/dist/studio.css +2272 -0
  311. package/dist/styles.js +1 -0
  312. package/package.json +88 -0
  313. package/prose-node-shims/fs.ts +6 -0
  314. package/prose-node-shims/path.ts +16 -0
  315. package/prose-node-shims/sharp.ts +4 -0
  316. package/prose-ui-node-shim.ts +26 -0
  317. package/src/App.tsx +173 -0
  318. package/src/WorkspaceRoutes.tsx +38 -0
  319. package/src/api.ts +833 -0
  320. package/src/auth-client.ts +15 -0
  321. package/src/chat/ChangeCard.tsx +330 -0
  322. package/src/chat/ChatBar.tsx +238 -0
  323. package/src/chat/ChatMessage.tsx +478 -0
  324. package/src/chat/ChatPanel.tsx +406 -0
  325. package/src/chat/ChatProvider.tsx +661 -0
  326. package/src/chat/Composer.tsx +461 -0
  327. package/src/chat/DocListCard.tsx +322 -0
  328. package/src/chat/LiveStatus.tsx +83 -0
  329. package/src/chat/MentionPopover.tsx +164 -0
  330. package/src/chat/ModelPicker.tsx +113 -0
  331. package/src/chat/Shimmer.tsx +39 -0
  332. package/src/chat/ThreadHistory.tsx +268 -0
  333. package/src/chat/chat-context.ts +41 -0
  334. package/src/chat/chat-helpers.ts +402 -0
  335. package/src/chat/chat-state.ts +59 -0
  336. package/src/chat/icons.tsx +171 -0
  337. package/src/chat/useStickToBottom.ts +110 -0
  338. package/src/chrome/AppShell.tsx +100 -0
  339. package/src/chrome/AppSidebar.tsx +305 -0
  340. package/src/chrome/CommandPalette.tsx +559 -0
  341. package/src/chrome/ContentApiPopover.tsx +215 -0
  342. package/src/chrome/EditorActionsContext.tsx +63 -0
  343. package/src/chrome/EditorFocusContext.tsx +80 -0
  344. package/src/chrome/EditorStatusContext.tsx +84 -0
  345. package/src/chrome/NavItem.tsx +75 -0
  346. package/src/chrome/OpenSiteButton.tsx +148 -0
  347. package/src/chrome/StatusBar.tsx +73 -0
  348. package/src/chrome/UserMenu.tsx +130 -0
  349. package/src/chrome/WorkspaceNavContext.tsx +60 -0
  350. package/src/chrome/WorkspaceStatusBar.tsx +940 -0
  351. package/src/chrome/content-api-url.ts +111 -0
  352. package/src/chrome/content-type-groups.ts +32 -0
  353. package/src/chrome/hotkeys.ts +79 -0
  354. package/src/chrome/icons.tsx +191 -0
  355. package/src/chrome/open-site.ts +30 -0
  356. package/src/chrome/status-bar-action.ts +24 -0
  357. package/src/components/AppChromeContext.tsx +32 -0
  358. package/src/components/Shell.tsx +18 -0
  359. package/src/components/WorkspaceSwitcher.tsx +345 -0
  360. package/src/content-blocks/index.tsx +262 -0
  361. package/src/css.d.ts +2 -0
  362. package/src/dashboard.ts +5 -0
  363. package/src/define-studio.tsx +98 -0
  364. package/src/define.ts +12 -0
  365. package/src/index.css +123 -0
  366. package/src/index.ts +19 -0
  367. package/src/last-user.ts +40 -0
  368. package/src/last-workspace.ts +57 -0
  369. package/src/mcp/McpConnectorsPanel.tsx +872 -0
  370. package/src/mcp/parse-json.ts +52 -0
  371. package/src/pages/AcceptInvitePage.tsx +99 -0
  372. package/src/pages/BlockSettingsDialog.tsx +303 -0
  373. package/src/pages/BlocksList.tsx +402 -0
  374. package/src/pages/BodyProse.tsx +236 -0
  375. package/src/pages/DocEditorPage.tsx +1394 -0
  376. package/src/pages/EmbedChatPage.tsx +110 -0
  377. package/src/pages/EmbedPublishPage.tsx +259 -0
  378. package/src/pages/EnterPage.tsx +96 -0
  379. package/src/pages/GithubConnectPage.tsx +142 -0
  380. package/src/pages/LegacyWorkspaceRedirect.tsx +57 -0
  381. package/src/pages/LoginPage.tsx +335 -0
  382. package/src/pages/NewWorkspacePage.tsx +74 -0
  383. package/src/pages/RenderedBody.tsx +598 -0
  384. package/src/pages/ResumeHome.tsx +18 -0
  385. package/src/pages/SelectionBar.tsx +277 -0
  386. package/src/pages/SettingsGeneralPage.tsx +403 -0
  387. package/src/pages/SettingsGithubPage.tsx +277 -0
  388. package/src/pages/SettingsLayout.tsx +127 -0
  389. package/src/pages/SettingsMcpPage.tsx +30 -0
  390. package/src/pages/SettingsSchemaPage.tsx +93 -0
  391. package/src/pages/SettingsUsersPage.tsx +363 -0
  392. package/src/pages/TypeDocsPage.tsx +225 -0
  393. package/src/pages/UiKitPage.tsx +331 -0
  394. package/src/pages/UserSettingsPage.tsx +94 -0
  395. package/src/pages/WorkspaceHomeRedirect.tsx +17 -0
  396. package/src/pages/WorkspaceLayout.tsx +103 -0
  397. package/src/pages/WorkspacesPage.tsx +35 -0
  398. package/src/pages/blocks-list.ts +73 -0
  399. package/src/pages/body-blocks.ts +233 -0
  400. package/src/pages/body-mdx.tsx +82 -0
  401. package/src/pages/compile-body.ts +37 -0
  402. package/src/pages/host-env.ts +22 -0
  403. package/src/pages/html-to-markdown.ts +99 -0
  404. package/src/pages/preview-bridge.ts +46 -0
  405. package/src/pages/preview-split.ts +30 -0
  406. package/src/pages/preview-url.ts +92 -0
  407. package/src/pages/selection-format.ts +179 -0
  408. package/src/pages/type-docs.ts +9 -0
  409. package/src/replica/BootstrapSplash.tsx +80 -0
  410. package/src/replica/ReplicaProvider.tsx +267 -0
  411. package/src/replica/cache.ts +30 -0
  412. package/src/replica/idb.ts +89 -0
  413. package/src/replica/instance.ts +39 -0
  414. package/src/replica/pull.ts +23 -0
  415. package/src/replica/store.ts +497 -0
  416. package/src/replica/sync-cache.ts +51 -0
  417. package/src/replica/types.ts +119 -0
  418. package/src/replica/useReplica.ts +13 -0
  419. package/src/site.tsx +230 -0
  420. package/src/studio-config.ts +81 -0
  421. package/src/styles/themes.ts +49 -0
  422. package/src/styles/tokens.stylex.ts +58 -0
  423. package/src/styles.ts +11 -0
  424. package/src/theme/AccentOverride.tsx +29 -0
  425. package/src/theme/ThemeProvider.tsx +130 -0
  426. package/src/theme/apply-theme-class.ts +12 -0
  427. package/src/ui/BackLink.tsx +28 -0
  428. package/src/ui/Button.tsx +167 -0
  429. package/src/ui/ConfirmDialog.tsx +141 -0
  430. package/src/ui/Field.tsx +45 -0
  431. package/src/ui/Input.tsx +183 -0
  432. package/src/ui/ListRow.tsx +88 -0
  433. package/src/ui/Page.tsx +151 -0
  434. package/src/ui/Text.tsx +77 -0
  435. package/src/ui/Tooltip.tsx +85 -0
  436. package/src/ui/popup.ts +216 -0
  437. package/src/workspace/permissions.ts +17 -0
  438. package/src/workspace/types.ts +12 -0
  439. package/src/workspace-path.ts +98 -0
@@ -0,0 +1,940 @@
1
+ // packages/studio/src/chrome/WorkspaceStatusBar.tsx
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { Link, useLocation } from "react-router";
4
+ import { canPublish } from "../workspace/permissions";
5
+ import { Combobox } from "@base-ui/react/combobox";
6
+ import { Popover } from "@base-ui/react/popover";
7
+ import * as stylex from "@stylexjs/stylex";
8
+ import {
9
+ commitWorkspace,
10
+ countConflicts,
11
+ createGitBranch,
12
+ defaultCommitMessage,
13
+ fetchGit,
14
+ notifyHeadChanged,
15
+ notifyTreeChanged,
16
+ publishCommittedFiles,
17
+ notifyWorkspaceChanged,
18
+ pullFromGithub,
19
+ resolveDoc,
20
+ type ApiError,
21
+ type ChangeStatus,
22
+ type GitChange,
23
+ } from "../api";
24
+ import { contentDocPath } from "../workspace-path";
25
+ import { CheckIcon } from "../chat/icons";
26
+ import { WorkspaceSwitcher } from "../components/WorkspaceSwitcher";
27
+ import { colors, radius, space, type } from "../styles/tokens.stylex";
28
+ import { cx, popup, popupClassName } from "../ui/popup";
29
+ import { useEditorStatus } from "./EditorStatusContext";
30
+ import { ContentApiPopover } from "./ContentApiPopover";
31
+ import { OpenSiteButton } from "./OpenSiteButton";
32
+ import { GitBranchIcon } from "./icons";
33
+ import { StatusBar, StatusItem, StatusSpacer } from "./StatusBar";
34
+ import { replicaStore } from "../replica/instance";
35
+ import { useReplicaSession } from "../replica/ReplicaProvider";
36
+ import { useReplicaState } from "../replica/useReplica";
37
+ import { useWorkspaceNav } from "./WorkspaceNavContext";
38
+ import { commitTriggerDisabled, statusBarAction } from "./status-bar-action";
39
+
40
+ const hover = "@media (hover: hover)";
41
+ const POLL_MS = 8000;
42
+
43
+ export const STATUS_LABEL: Record<ChangeStatus, string> = {
44
+ modified: "modified",
45
+ added: "new",
46
+ conflict: "conflict",
47
+ deleted: "deleted",
48
+ };
49
+
50
+ function formatCommitError(err: unknown): string {
51
+ if (!(err instanceof Error)) return "Commit failed";
52
+ const apiErr = err as ApiError;
53
+ if (apiErr.code === "conflict") return "Resolve conflicts before committing";
54
+ if (apiErr.code === "nothing_to_commit") return "Nothing to commit";
55
+ if (apiErr.code === "validation") {
56
+ return err.message.replace(/^validation:\s*/, "Validation failed: ");
57
+ }
58
+ if (apiErr.code === "github_not_bound") return "Connect GitHub first";
59
+ return err.message;
60
+ }
61
+
62
+ function changeKey(doc: GitChange) {
63
+ return `${doc.locale}/${doc.type}/${doc.slug}`;
64
+ }
65
+
66
+ function ConflictResolvePanel({
67
+ workspaceSlug,
68
+ defaultLocale,
69
+ conflicts,
70
+ resolvingKey,
71
+ error,
72
+ onOpenDoc,
73
+ onResolve,
74
+ }: {
75
+ workspaceSlug: string | null;
76
+ defaultLocale: string;
77
+ conflicts: GitChange[];
78
+ resolvingKey: string | null;
79
+ error: string | null;
80
+ onOpenDoc: () => void;
81
+ onResolve: (doc: GitChange, strategy: "mine" | "theirs") => void;
82
+ }) {
83
+ return (
84
+ <div {...stylex.props(styles.commitForm)}>
85
+ <p {...stylex.props(popup.groupLabel)}>Resolve conflicts</p>
86
+ <p {...stylex.props(styles.conflictHint)}>
87
+ Pick a side for each file. Commit stays blocked until every conflict is
88
+ resolved.
89
+ </p>
90
+ {error ? <p {...stylex.props(styles.conflictError)}>{error}</p> : null}
91
+ <ul {...stylex.props(styles.commitFiles, styles.conflictList)}>
92
+ {conflicts.map((doc) => {
93
+ const key = changeKey(doc);
94
+ const href = workspaceSlug
95
+ ? contentDocPath(
96
+ workspaceSlug,
97
+ doc.type,
98
+ doc.slug,
99
+ doc.locale,
100
+ defaultLocale,
101
+ )
102
+ : null;
103
+ return (
104
+ <li key={key} {...stylex.props(styles.conflictRow)}>
105
+ {href ? (
106
+ <Link
107
+ to={href}
108
+ onClick={onOpenDoc}
109
+ {...stylex.props(styles.conflictLink)}
110
+ >
111
+ <span {...stylex.props(styles.changeName)}>
112
+ {doc.type}/{doc.slug}
113
+ </span>
114
+ <span {...stylex.props(popup.itemMeta)}>{doc.locale}</span>
115
+ </Link>
116
+ ) : (
117
+ <span {...stylex.props(styles.changeName)}>
118
+ {doc.type}/{doc.slug}
119
+ </span>
120
+ )}
121
+ <div {...stylex.props(styles.conflictActions)}>
122
+ <button
123
+ type="button"
124
+ disabled={resolvingKey !== null}
125
+ onClick={() => onResolve(doc, "mine")}
126
+ {...stylex.props(styles.conflictBtn)}
127
+ >
128
+ {resolvingKey === `${key}:mine` ? "Keeping…" : "Keep mine"}
129
+ </button>
130
+ <button
131
+ type="button"
132
+ disabled={resolvingKey !== null}
133
+ onClick={() => onResolve(doc, "theirs")}
134
+ {...stylex.props(styles.conflictBtn, styles.conflictBtnDanger)}
135
+ >
136
+ {resolvingKey === `${key}:theirs` ? "Taking…" : "Take theirs"}
137
+ </button>
138
+ </div>
139
+ </li>
140
+ );
141
+ })}
142
+ </ul>
143
+ </div>
144
+ );
145
+ }
146
+
147
+ function ChangeRow({ doc }: { doc: GitChange }) {
148
+ return (
149
+ <div {...stylex.props(styles.changeItem)}>
150
+ <span {...stylex.props(styles.changeName)}>
151
+ {doc.type}/{doc.slug}
152
+ </span>
153
+ <span
154
+ {...stylex.props(
155
+ popup.itemMeta,
156
+ doc.status === "conflict" && styles.conflictText,
157
+ )}
158
+ >
159
+ {STATUS_LABEL[doc.status]}
160
+ </span>
161
+ </div>
162
+ );
163
+ }
164
+
165
+ export function WorkspaceStatusBar({ workspaceId }: { workspaceId: string }) {
166
+ const location = useLocation();
167
+ const editor = useEditorStatus();
168
+ const workspaceNav = useWorkspaceNav();
169
+ const publish = canPublish(workspaceNav?.role ?? "");
170
+ const { applyCheckout, syncCheckout } = useReplicaSession();
171
+ const replica = useReplicaState();
172
+ const refreshError = replica.refreshError;
173
+ const git = replica.git(workspaceId);
174
+ const [open, setOpen] = useState(false);
175
+ const [creating, setCreating] = useState(false);
176
+ const [newName, setNewName] = useState("");
177
+ const [syncing, setSyncing] = useState(false);
178
+ const [pulling, setPulling] = useState(false);
179
+ const [commitOpen, setCommitOpen] = useState(false);
180
+ const [committing, setCommitting] = useState(false);
181
+ const [resolvingKey, setResolvingKey] = useState<string | null>(null);
182
+ const [message, setMessage] = useState("");
183
+ const [error, setError] = useState<string | null>(null);
184
+ // HEAD identity from the last poll so we can announce "HEAD moved".
185
+ const lastHead = useRef<string | null | undefined>(undefined);
186
+
187
+ async function reloadGit() {
188
+ try {
189
+ const next = await fetchGit(workspaceId);
190
+ replicaStore.setGit(workspaceId, next);
191
+ if (next.githubError === "installation_missing") {
192
+ setError("GitHub installation was removed. Reconnect in settings.");
193
+ } else if (next.githubError) {
194
+ setError("Couldn't load branches from GitHub");
195
+ } else {
196
+ setError(null);
197
+ }
198
+ const headKey = next.head ? `${next.head.sha}:${next.head.updatedAt}` : null;
199
+ if (lastHead.current !== undefined && lastHead.current !== headKey) {
200
+ notifyHeadChanged();
201
+ }
202
+ lastHead.current = headKey;
203
+ } catch (err) {
204
+ setError(err instanceof Error ? err.message : "Git status failed");
205
+ }
206
+ }
207
+
208
+ useEffect(() => {
209
+ lastHead.current = undefined;
210
+ void reloadGit();
211
+ const onChange = () => {
212
+ void reloadGit();
213
+ };
214
+ window.addEventListener("backmatter:tree-changed", onChange);
215
+ window.addEventListener("backmatter:workspace-changed", onChange);
216
+ const timer = window.setInterval(() => {
217
+ void reloadGit();
218
+ }, POLL_MS);
219
+ return () => {
220
+ window.removeEventListener("backmatter:tree-changed", onChange);
221
+ window.removeEventListener("backmatter:workspace-changed", onChange);
222
+ window.clearInterval(timer);
223
+ };
224
+ // eslint-disable-next-line react-hooks/exhaustive-deps
225
+ }, [workspaceId]);
226
+
227
+ const branchNames = useMemo(() => (git?.branches ?? []).map((b) => b.name), [git]);
228
+ const changes = git?.changes ?? [];
229
+ const changeCount = changes.length;
230
+ const conflictCount = countConflicts(git);
231
+ const action = statusBarAction(conflictCount, publish);
232
+ const conflicts = useMemo(
233
+ () => changes.filter((doc) => doc.status === "conflict"),
234
+ [changes],
235
+ );
236
+ const inEditor = /\/content\/[^/]+\/[^/]+\/?$/.test(location.pathname);
237
+
238
+ async function onCheckout(branch: string) {
239
+ if (!branch || branch === git?.currentBranch) {
240
+ setOpen(false);
241
+ return;
242
+ }
243
+ setSyncing(true);
244
+ setError(null);
245
+ try {
246
+ await applyCheckout(workspaceId, branch);
247
+ await reloadGit();
248
+ setOpen(false);
249
+ } catch (err) {
250
+ setError(err instanceof Error ? err.message : "Checkout failed");
251
+ } finally {
252
+ setSyncing(false);
253
+ }
254
+ }
255
+
256
+ async function onCreate(e: React.FormEvent) {
257
+ e.preventDefault();
258
+ const name = newName.trim();
259
+ if (!name) return;
260
+ setSyncing(true);
261
+ setError(null);
262
+ try {
263
+ await createGitBranch(workspaceId, { name });
264
+ notifyWorkspaceChanged();
265
+ await syncCheckout(workspaceId, name);
266
+ await reloadGit();
267
+ setCreating(false);
268
+ setNewName("");
269
+ setOpen(false);
270
+ } catch (err) {
271
+ setError(err instanceof Error ? err.message : "Create branch failed");
272
+ } finally {
273
+ setSyncing(false);
274
+ }
275
+ }
276
+
277
+ async function onPull() {
278
+ setPulling(true);
279
+ setError(null);
280
+ try {
281
+ await pullFromGithub(workspaceId);
282
+ notifyHeadChanged();
283
+ await reloadGit();
284
+ setOpen(false);
285
+ } catch (err) {
286
+ setError(err instanceof Error ? err.message : "Pull failed");
287
+ } finally {
288
+ setPulling(false);
289
+ }
290
+ }
291
+
292
+ async function onResolveConflict(
293
+ doc: GitChange,
294
+ strategy: "mine" | "theirs",
295
+ ) {
296
+ const key = `${changeKey(doc)}:${strategy}`;
297
+ setResolvingKey(key);
298
+ setError(null);
299
+ try {
300
+ await resolveDoc(workspaceId, doc.locale, doc.type, doc.slug, strategy);
301
+ notifyTreeChanged({
302
+ workspaceId,
303
+ locale: doc.locale,
304
+ type: doc.type,
305
+ slug: doc.slug,
306
+ status: strategy === "theirs" ? "clean" : "modified",
307
+ });
308
+ const stillConflicted = changes.some(
309
+ (other) =>
310
+ other.status === "conflict" && changeKey(other) !== changeKey(doc),
311
+ );
312
+ if (!stillConflicted) setCommitOpen(false);
313
+ await reloadGit();
314
+ } catch (err) {
315
+ setError(err instanceof Error ? err.message : "Resolve failed");
316
+ } finally {
317
+ setResolvingKey(null);
318
+ }
319
+ }
320
+
321
+ async function onCommit(e?: React.FormEvent) {
322
+ e?.preventDefault();
323
+ if (committing || conflictCount > 0 || changeCount === 0) return;
324
+ setCommitting(true);
325
+ setError(null);
326
+ try {
327
+ const result = await commitWorkspace(workspaceId, message);
328
+ setMessage("");
329
+ setCommitOpen(false);
330
+ publishCommittedFiles(workspaceId, result.files);
331
+ await reloadGit();
332
+ } catch (err) {
333
+ setError(formatCommitError(err));
334
+ await reloadGit();
335
+ } finally {
336
+ setCommitting(false);
337
+ }
338
+ }
339
+
340
+ const commitLabel = committing
341
+ ? "Committing…"
342
+ : conflictCount > 0
343
+ ? `Resolve ${conflictCount} ${conflictCount === 1 ? "conflict" : "conflicts"}`
344
+ : `Deploy ${changeCount} changes`;
345
+
346
+ return (
347
+ <StatusBar>
348
+ <div {...stylex.props(styles.identity)}>
349
+ {workspaceNav ? (
350
+ <WorkspaceSwitcher
351
+ workspaceId={workspaceNav.workspaceId}
352
+ workspaceName={workspaceNav.workspaceName}
353
+ />
354
+ ) : (
355
+ <StatusItem>—</StatusItem>
356
+ )}
357
+ <span {...stylex.props(styles.divider)} aria-hidden />
358
+ <Combobox.Root
359
+ items={branchNames}
360
+ value={git?.currentBranch ?? null}
361
+ onValueChange={(name) => {
362
+ if (typeof name === "string") void onCheckout(name);
363
+ }}
364
+ open={open}
365
+ onOpenChange={(next) => {
366
+ setOpen(next);
367
+ if (!next) setCreating(false);
368
+ }}
369
+ >
370
+ <Combobox.Trigger
371
+ aria-label={`Current branch ${git?.currentBranch ?? "none"}`}
372
+ disabled={syncing}
373
+ className={cx(styles.barBtn)}
374
+ >
375
+ <GitBranchIcon />
376
+ <span {...stylex.props(styles.branchName)}>
377
+ {syncing ? "Syncing…" : pulling ? "Pulling…" : git?.currentBranch ?? "—"}
378
+ </span>
379
+ </Combobox.Trigger>
380
+ <Combobox.Portal>
381
+ <Combobox.Positioner
382
+ side="bottom"
383
+ align="start"
384
+ sideOffset={6}
385
+ className={cx(popup.positioner)}
386
+ >
387
+ <Combobox.Popup
388
+ aria-label="Branches"
389
+ className={(state) => popupClassName(state, styles.menu)}
390
+ >
391
+ <Combobox.Input
392
+ placeholder="Filter branches"
393
+ aria-label="Filter branches"
394
+ autoComplete="off"
395
+ spellCheck={false}
396
+ data-no-ring
397
+ data-1p-ignore
398
+ data-lpignore
399
+ className={cx(popup.searchInput)}
400
+ />
401
+ <Combobox.Empty className={cx(popup.empty)}>No branches</Combobox.Empty>
402
+ <Combobox.List className={cx(styles.list)}>
403
+ {(name: string) => (
404
+ <Combobox.Item
405
+ key={name}
406
+ value={name}
407
+ className={(state) =>
408
+ cx(
409
+ popup.item,
410
+ styles.option,
411
+ state.highlighted && popup.itemHighlighted,
412
+ state.selected && popup.itemSelected,
413
+ )
414
+ }
415
+ >
416
+ <span {...stylex.props(popup.itemIndicator)}>
417
+ <Combobox.ItemIndicator>
418
+ <CheckIcon size={12} />
419
+ </Combobox.ItemIndicator>
420
+ </span>
421
+ <span {...stylex.props(styles.optionName)}>{name}</span>
422
+ {name === git?.defaultBranch ? (
423
+ <span {...stylex.props(popup.itemMeta)}>default</span>
424
+ ) : null}
425
+ </Combobox.Item>
426
+ )}
427
+ </Combobox.List>
428
+ {changes.length > 0 ? (
429
+ <>
430
+ <div {...stylex.props(popup.separator)} />
431
+ <div {...stylex.props(styles.changes)}>
432
+ <p {...stylex.props(popup.groupLabel)}>Uncommitted</p>
433
+ {changes.map((doc) => (
434
+ <ChangeRow key={`${doc.locale}/${doc.type}/${doc.slug}`} doc={doc} />
435
+ ))}
436
+ </div>
437
+ </>
438
+ ) : null}
439
+ <div {...stylex.props(popup.separator)} />
440
+ <button
441
+ type="button"
442
+ disabled={pulling || syncing}
443
+ onClick={() => void onPull()}
444
+ className={cx(popup.item, popup.action)}
445
+ >
446
+ {pulling ? "Pulling from GitHub…" : "Pull from GitHub"}
447
+ </button>
448
+ {creating ? (
449
+ <form onSubmit={(e) => void onCreate(e)} {...stylex.props(styles.create)}>
450
+ <input
451
+ value={newName}
452
+ onChange={(e) => setNewName(e.target.value)}
453
+ // Keep list navigation from swallowing keys typed here.
454
+ onKeyDown={(e) => {
455
+ if (e.key !== "Escape") e.stopPropagation();
456
+ }}
457
+ placeholder="feat/…"
458
+ aria-label="New branch name"
459
+ autoComplete="off"
460
+ spellCheck={false}
461
+ data-no-ring
462
+ data-1p-ignore
463
+ data-lpignore
464
+ autoFocus
465
+ {...stylex.props(popup.quietInput, styles.createInput)}
466
+ />
467
+ <button type="submit" className={cx(popup.item, popup.action)}>
468
+ Create
469
+ </button>
470
+ </form>
471
+ ) : (
472
+ <button
473
+ type="button"
474
+ onClick={() => setCreating(true)}
475
+ className={cx(popup.item, popup.action)}
476
+ >
477
+ Create branch from current…
478
+ </button>
479
+ )}
480
+ </Combobox.Popup>
481
+ </Combobox.Positioner>
482
+ </Combobox.Portal>
483
+ </Combobox.Root>
484
+ {workspaceNav?.workspaceId ? (
485
+ <>
486
+ <span {...stylex.props(styles.divider)} aria-hidden />
487
+ <ContentApiPopover
488
+ workspaceId={workspaceNav.workspaceId}
489
+ branch={git?.currentBranch}
490
+ defaultBranch={git?.defaultBranch}
491
+ pathname={location.pathname}
492
+ search={location.search}
493
+ />
494
+ {replica.sessionUserId ? (
495
+ <OpenSiteButton
496
+ workspaceId={workspaceNav.workspaceId}
497
+ userId={replica.sessionUserId}
498
+ siteUrls={workspaceNav.siteUrls}
499
+ />
500
+ ) : null}
501
+ </>
502
+ ) : null}
503
+ </div>
504
+ {changeCount > 0 ? (
505
+ <StatusItem tone={conflictCount > 0 ? "danger" : "muted"}>
506
+ {changeCount} uncommitted
507
+ </StatusItem>
508
+ ) : null}
509
+ {error ? <StatusItem tone="danger">{error}</StatusItem> : null}
510
+ {refreshError && !error ? (
511
+ <StatusItem tone="danger">{refreshError}</StatusItem>
512
+ ) : null}
513
+ <StatusSpacer />
514
+ {inEditor && editor.saveLabel ? (
515
+ <StatusItem tone={editor.saveTone}>{editor.saveLabel}</StatusItem>
516
+ ) : null}
517
+ {changeCount > 0 ? (
518
+ <Popover.Root
519
+ open={commitOpen}
520
+ onOpenChange={(next) => {
521
+ if (action === "blocked") return;
522
+ setCommitOpen(next);
523
+ }}
524
+ >
525
+ <Popover.Trigger
526
+ disabled={commitTriggerDisabled(action, { committing, syncing })}
527
+ aria-label={
528
+ action === "blocked"
529
+ ? "Writers cannot publish"
530
+ : action === "resolve"
531
+ ? commitLabel
532
+ : `Commit ${changeCount} ${changeCount === 1 ? "file" : "files"}`
533
+ }
534
+ title={action === "blocked" ? "Writers cannot publish" : undefined}
535
+ className={cx(styles.commit, action === "resolve" && styles.commitBlocked)}
536
+ >
537
+ {commitLabel}
538
+ </Popover.Trigger>
539
+ <Popover.Portal>
540
+ <Popover.Positioner
541
+ side="bottom"
542
+ align="end"
543
+ sideOffset={6}
544
+ className={cx(popup.positioner)}
545
+ >
546
+ <Popover.Popup
547
+ aria-label={action === "resolve" ? "Resolve conflicts" : "Commit changes"}
548
+ className={(state) => popupClassName(state, styles.commitPopup)}
549
+ >
550
+ {action === "resolve" ? (
551
+ <ConflictResolvePanel
552
+ workspaceSlug={workspaceNav?.workspaceSlug ?? null}
553
+ defaultLocale={workspaceNav?.defaultLocale ?? "en"}
554
+ conflicts={conflicts}
555
+ resolvingKey={resolvingKey}
556
+ error={error}
557
+ onOpenDoc={() => setCommitOpen(false)}
558
+ onResolve={(doc, strategy) => void onResolveConflict(doc, strategy)}
559
+ />
560
+ ) : (
561
+ <form onSubmit={(e) => void onCommit(e)} {...stylex.props(styles.commitForm)}>
562
+ <p {...stylex.props(popup.groupLabel)}>
563
+ {changeCount} {changeCount === 1 ? "file" : "files"} → {git?.currentBranch}
564
+ </p>
565
+ <ul {...stylex.props(styles.commitFiles)}>
566
+ {changes.map((doc) => (
567
+ <li key={`${doc.locale}/${doc.type}/${doc.slug}`}>
568
+ <ChangeRow doc={doc} />
569
+ </li>
570
+ ))}
571
+ </ul>
572
+ <div {...stylex.props(popup.separator)} />
573
+ <div {...stylex.props(styles.commitFooter)}>
574
+ <input
575
+ value={message}
576
+ onChange={(e) => setMessage(e.target.value)}
577
+ placeholder={defaultCommitMessage(changes)}
578
+ aria-label="Commit message"
579
+ autoComplete="off"
580
+ spellCheck={false}
581
+ data-no-ring
582
+ data-1p-ignore
583
+ data-lpignore
584
+ autoFocus
585
+ disabled={committing}
586
+ {...stylex.props(styles.commitField)}
587
+ />
588
+ <div {...stylex.props(styles.commitSubmit)}>
589
+ {/* <span {...stylex.props(styles.commitHint)}>
590
+ Empty message uses the default
591
+ </span> */}
592
+ <button
593
+ type="submit"
594
+ disabled={committing}
595
+ {...stylex.props(styles.commitSubmitBtn)}
596
+ >
597
+ {committing ? "Committing…" : "Commit & push"}
598
+ </button>
599
+ </div>
600
+ </div>
601
+ </form>
602
+ )}
603
+ </Popover.Popup>
604
+ </Popover.Positioner>
605
+ </Popover.Portal>
606
+ </Popover.Root>
607
+ ) : null}
608
+ </StatusBar>
609
+ );
610
+ }
611
+
612
+ const styles = stylex.create({
613
+ identity: {
614
+ display: "flex",
615
+ minWidth: 0,
616
+ alignItems: "center",
617
+ gap: space.xs,
618
+ },
619
+ divider: {
620
+ width: 1,
621
+ height: "12px",
622
+ flexShrink: 0,
623
+ backgroundColor: colors.border,
624
+ },
625
+ barBtn: {
626
+ display: "inline-flex",
627
+ alignItems: "center",
628
+ gap: space.xs,
629
+ minHeight: "24px",
630
+ paddingInline: space.xs,
631
+ borderWidth: 0,
632
+ backgroundColor: "transparent",
633
+ color: colors.textMuted,
634
+ fontSize: type.xs,
635
+ fontFamily: type.mono,
636
+ cursor: "pointer",
637
+ ":focus-visible": {
638
+ outlineWidth: 2,
639
+ outlineStyle: "solid",
640
+ outlineColor: colors.focus,
641
+ outlineOffset: "-2px",
642
+ },
643
+ [hover]: {
644
+ ":hover": {
645
+ color: colors.text,
646
+ },
647
+ },
648
+ },
649
+ branchName: {
650
+ maxWidth: "180px",
651
+ overflow: "hidden",
652
+ textOverflow: "ellipsis",
653
+ whiteSpace: "nowrap",
654
+ },
655
+ menu: {
656
+ width: "280px",
657
+ display: "flex",
658
+ flexDirection: "column",
659
+ overflow: "hidden",
660
+ },
661
+ list: {
662
+ maxHeight: "220px",
663
+ overflowY: "auto",
664
+ paddingBottom: space.xs,
665
+ },
666
+ option: {
667
+ fontFamily: type.mono,
668
+ fontSize: type.xs,
669
+ cursor: "pointer",
670
+ },
671
+ optionName: {
672
+ minWidth: 0,
673
+ overflow: "hidden",
674
+ textOverflow: "ellipsis",
675
+ whiteSpace: "nowrap",
676
+ },
677
+ changes: {
678
+ maxHeight: "160px",
679
+ overflowY: "auto",
680
+ paddingBottom: space.xs,
681
+ },
682
+ changeItem: {
683
+ display: "flex",
684
+ alignItems: "center",
685
+ gap: space.sm,
686
+ minHeight: 30,
687
+ margin: 0,
688
+ marginInline: space.xs,
689
+ paddingInline: space.md,
690
+ paddingBlock: space.sm,
691
+ fontFamily: type.mono,
692
+ fontSize: type.xs,
693
+ color: colors.textMuted,
694
+ },
695
+ changeName: {
696
+ minWidth: 0,
697
+ flex: 1,
698
+ overflow: "hidden",
699
+ textOverflow: "ellipsis",
700
+ whiteSpace: "nowrap",
701
+ },
702
+ conflictText: {
703
+ color: colors.danger,
704
+ },
705
+ conflictHint: {
706
+ margin: 0,
707
+ paddingInline: space.lg,
708
+ paddingBottom: space.sm,
709
+ fontSize: type.xs,
710
+ lineHeight: 1.4,
711
+ color: colors.textMuted,
712
+ },
713
+ conflictError: {
714
+ margin: 0,
715
+ paddingInline: space.lg,
716
+ paddingBottom: space.sm,
717
+ fontSize: type.xs,
718
+ color: colors.danger,
719
+ },
720
+ conflictList: {
721
+ maxHeight: "280px",
722
+ },
723
+ conflictRow: {
724
+ display: "flex",
725
+ flexDirection: "column",
726
+ gap: space.xs,
727
+ paddingInline: space.md,
728
+ paddingBlock: space.sm,
729
+ },
730
+ conflictLink: {
731
+ display: "flex",
732
+ alignItems: "center",
733
+ gap: space.sm,
734
+ minWidth: 0,
735
+ color: colors.text,
736
+ fontFamily: type.mono,
737
+ fontSize: type.xs,
738
+ textDecoration: "none",
739
+ [hover]: {
740
+ ":hover": {
741
+ textDecoration: "underline",
742
+ },
743
+ },
744
+ },
745
+ conflictActions: {
746
+ display: "flex",
747
+ gap: space.xs,
748
+ },
749
+ conflictBtn: {
750
+ height: 24,
751
+ paddingInline: space.md,
752
+ borderWidth: 1,
753
+ borderStyle: "solid",
754
+ borderColor: colors.border,
755
+ borderRadius: radius.md,
756
+ backgroundColor: colors.bgSurface,
757
+ color: colors.text,
758
+ fontSize: type.xs,
759
+ cursor: "pointer",
760
+ ":disabled": {
761
+ opacity: 0.55,
762
+ cursor: "not-allowed",
763
+ },
764
+ ":focus-visible": {
765
+ outlineWidth: 2,
766
+ outlineStyle: "solid",
767
+ outlineColor: colors.focus,
768
+ outlineOffset: 1,
769
+ },
770
+ },
771
+ conflictBtnDanger: {
772
+ borderColor: colors.danger,
773
+ color: colors.danger,
774
+ },
775
+ create: {
776
+ display: "flex",
777
+ flexDirection: "column",
778
+ gap: space.xs,
779
+ },
780
+ createInput: {
781
+ fontFamily: type.mono,
782
+ fontSize: type.xs,
783
+ },
784
+ commit: {
785
+ display: "inline-flex",
786
+ alignItems: "center",
787
+ height: 24,
788
+ paddingInline: space.md,
789
+ borderWidth: 1,
790
+ borderStyle: "solid",
791
+ borderColor: colors.accent,
792
+ borderRadius: radius.md,
793
+ backgroundColor: colors.accent,
794
+ color: colors.textInverse,
795
+ fontSize: type.xs,
796
+ fontWeight: 500,
797
+ whiteSpace: "nowrap",
798
+ cursor: "pointer",
799
+ [hover]: {
800
+ ":hover": {
801
+ backgroundColor: colors.accentHover,
802
+ borderColor: colors.accentHover,
803
+ },
804
+ },
805
+ ":disabled": {
806
+ opacity: 0.55,
807
+ cursor: "not-allowed",
808
+ },
809
+ ":active": {
810
+ transform: "scale(0.97)",
811
+ },
812
+ ":focus-visible": {
813
+ outlineWidth: 2,
814
+ outlineStyle: "solid",
815
+ outlineColor: colors.focus,
816
+ outlineOffset: 1,
817
+ },
818
+ "@media (prefers-reduced-motion: reduce)": {
819
+ ":active": {
820
+ transform: "none",
821
+ },
822
+ },
823
+ },
824
+ commitBlocked: {
825
+ borderColor: colors.danger,
826
+ backgroundColor: colors.danger,
827
+ ":disabled": {
828
+ opacity: 0.8,
829
+ },
830
+ },
831
+ commitPopup: {
832
+ width: "320px",
833
+ paddingBlock: 0,
834
+ overflow: "hidden",
835
+ },
836
+ commitForm: {
837
+ display: "flex",
838
+ flexDirection: "column",
839
+ paddingTop: space.xs,
840
+ },
841
+ commitFiles: {
842
+ margin: 0,
843
+ padding: 0,
844
+ listStyle: "none",
845
+ maxHeight: "160px",
846
+ overflowY: "auto",
847
+ paddingBottom: space.xs,
848
+ },
849
+ commitFooter: {
850
+ display: "flex",
851
+ flexDirection: "column",
852
+ alignItems: "stretch",
853
+ gap: space.md,
854
+ paddingInline: space.lg,
855
+ paddingTop: space.md,
856
+ paddingBottom: space.lg,
857
+ },
858
+ commitField: {
859
+ width: "100%",
860
+ boxSizing: "border-box",
861
+ minHeight: "28px",
862
+ paddingInline: space.md,
863
+ paddingBlock: space.sm,
864
+ borderWidth: 1,
865
+ borderStyle: "solid",
866
+ borderColor: colors.border,
867
+ borderRadius: radius.md,
868
+ backgroundColor: colors.bgInput,
869
+ color: colors.text,
870
+ fontSize: type.sm,
871
+ outline: "none",
872
+ ":focus": {
873
+ outline: "none",
874
+ borderColor: `color-mix(in srgb, ${colors.textMuted} 45%, ${colors.border})`,
875
+ },
876
+ ":focus-visible": {
877
+ outline: "none",
878
+ },
879
+ ":disabled": {
880
+ opacity: 0.55,
881
+ },
882
+ "::placeholder": {
883
+ color: colors.textMuted,
884
+ },
885
+ },
886
+ commitHint: {
887
+ minWidth: 0,
888
+ fontSize: type.xs,
889
+ color: colors.textMuted,
890
+ },
891
+ commitSubmit: {
892
+ display: "flex",
893
+ alignItems: "center",
894
+ justifyContent: "space-between",
895
+ gap: space.md,
896
+ },
897
+ commitSubmitBtn: {
898
+ display: "flex",
899
+ width: "100%",
900
+ flexShrink: 0,
901
+ alignItems: "center",
902
+ justifyContent: "center",
903
+ height: 28,
904
+ paddingInline: space.xl,
905
+ borderWidth: 1,
906
+ borderStyle: "solid",
907
+ borderColor: colors.accent,
908
+ borderRadius: radius.md,
909
+ backgroundColor: colors.accent,
910
+ color: colors.textInverse,
911
+ fontSize: type.xs,
912
+ fontWeight: 500,
913
+ whiteSpace: "nowrap",
914
+ cursor: "pointer",
915
+ [hover]: {
916
+ ":hover": {
917
+ backgroundColor: colors.accentHover,
918
+ borderColor: colors.accentHover,
919
+ },
920
+ },
921
+ ":disabled": {
922
+ opacity: 0.55,
923
+ cursor: "not-allowed",
924
+ },
925
+ ":active": {
926
+ transform: "scale(0.97)",
927
+ },
928
+ ":focus-visible": {
929
+ outlineWidth: 2,
930
+ outlineStyle: "solid",
931
+ outlineColor: colors.focus,
932
+ outlineOffset: 1,
933
+ },
934
+ "@media (prefers-reduced-motion: reduce)": {
935
+ ":active": {
936
+ transform: "none",
937
+ },
938
+ },
939
+ },
940
+ });