waybetter 0.1.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (515) hide show
  1. package/README.md +143 -9
  2. package/bin/waybetter.mjs +46 -0
  3. package/build/runtime.mjs +105 -0
  4. package/cli/buildenv.mjs +130 -0
  5. package/cli/dev.mjs +97 -0
  6. package/cli/i18n.mjs +382 -0
  7. package/cli/manifests.mjs +383 -0
  8. package/cli/privacy.mjs +768 -0
  9. package/cli/release.mjs +444 -0
  10. package/cli/remote.mjs +260 -0
  11. package/cli/store.mjs +326 -0
  12. package/cli/strings.mjs +121 -0
  13. package/dist/runtime/column.d.ts +93 -0
  14. package/dist/runtime/column.js +451 -0
  15. package/dist/runtime/column.js.map +1 -0
  16. package/dist/runtime/commandReport.d.ts +19 -0
  17. package/dist/runtime/commandReport.js +47 -0
  18. package/dist/runtime/commandReport.js.map +1 -0
  19. package/dist/runtime/commands.d.ts +72 -0
  20. package/dist/runtime/commands.js +214 -0
  21. package/dist/runtime/commands.js.map +1 -0
  22. package/dist/runtime/devErrors.d.ts +16 -0
  23. package/dist/runtime/devErrors.js +30 -0
  24. package/dist/runtime/devErrors.js.map +1 -0
  25. package/dist/runtime/domHub.d.ts +21 -0
  26. package/dist/runtime/domHub.js +139 -4
  27. package/dist/runtime/domHub.js.map +1 -1
  28. package/dist/runtime/featureModules.d.ts +157 -0
  29. package/dist/runtime/featureModules.js +484 -0
  30. package/dist/runtime/featureModules.js.map +1 -0
  31. package/dist/runtime/featureTable.d.ts +144 -0
  32. package/dist/runtime/featureTable.js +223 -0
  33. package/dist/runtime/featureTable.js.map +1 -0
  34. package/dist/runtime/fonts.d.ts +22 -0
  35. package/dist/runtime/fonts.js +72 -0
  36. package/dist/runtime/fonts.js.map +1 -0
  37. package/dist/runtime/i18n.d.ts +138 -0
  38. package/dist/runtime/i18n.js +614 -0
  39. package/dist/runtime/i18n.js.map +1 -0
  40. package/dist/runtime/i18nCheck.d.ts +30 -0
  41. package/dist/runtime/i18nCheck.js +224 -0
  42. package/dist/runtime/i18nCheck.js.map +1 -0
  43. package/dist/runtime/pageLang.d.ts +8 -0
  44. package/dist/runtime/pageLang.js +64 -0
  45. package/dist/runtime/pageLang.js.map +1 -0
  46. package/dist/runtime/pageStrings.d.ts +35 -0
  47. package/dist/runtime/pageStrings.js +76 -0
  48. package/dist/runtime/pageStrings.js.map +1 -0
  49. package/dist/runtime/panelButton.d.ts +33 -0
  50. package/dist/runtime/panelButton.js +83 -0
  51. package/dist/runtime/panelButton.js.map +1 -0
  52. package/dist/runtime/permissions.d.ts +47 -0
  53. package/dist/runtime/permissions.js +141 -0
  54. package/dist/runtime/permissions.js.map +1 -0
  55. package/dist/runtime/pluginApi.d.ts +51 -2
  56. package/dist/runtime/pluginApi.js +137 -22
  57. package/dist/runtime/pluginApi.js.map +1 -1
  58. package/dist/runtime/pluginI18n.d.ts +29 -0
  59. package/dist/runtime/pluginI18n.js +119 -0
  60. package/dist/runtime/pluginI18n.js.map +1 -0
  61. package/dist/runtime/settingsForm.d.ts +66 -0
  62. package/dist/runtime/settingsForm.js +114 -0
  63. package/dist/runtime/settingsForm.js.map +1 -0
  64. package/dist/runtime/site.d.ts +5 -0
  65. package/dist/runtime/site.js +1 -1
  66. package/dist/runtime/site.js.map +1 -1
  67. package/dist/runtime/siteRuntime.d.ts +144 -0
  68. package/dist/runtime/siteRuntime.js +175 -0
  69. package/dist/runtime/siteRuntime.js.map +1 -0
  70. package/dist/runtime/stringPackHook.d.ts +84 -0
  71. package/dist/runtime/stringPackHook.js +220 -0
  72. package/dist/runtime/stringPackHook.js.map +1 -0
  73. package/dist/runtime/stringPackTranslate.d.ts +59 -0
  74. package/dist/runtime/stringPackTranslate.js +264 -0
  75. package/dist/runtime/stringPackTranslate.js.map +1 -0
  76. package/dist/runtime/stringPacks.d.ts +200 -0
  77. package/dist/runtime/stringPacks.js +474 -0
  78. package/dist/runtime/stringPacks.js.map +1 -0
  79. package/dist/runtime/styles.d.ts +15 -0
  80. package/dist/runtime/styles.js +81 -0
  81. package/dist/runtime/styles.js.map +1 -0
  82. package/dist/runtime/textNet.d.ts +15 -0
  83. package/dist/runtime/textNet.js +131 -0
  84. package/dist/runtime/textNet.js.map +1 -0
  85. package/dist/runtime/themeApi.d.ts +121 -0
  86. package/dist/runtime/themeApi.js +220 -0
  87. package/dist/runtime/themeApi.js.map +1 -0
  88. package/dist/runtime/themeChoice.d.ts +52 -0
  89. package/dist/runtime/themeChoice.js +69 -0
  90. package/dist/runtime/themeChoice.js.map +1 -0
  91. package/dist/runtime/themeComponents.d.ts +435 -0
  92. package/dist/runtime/themeComponents.js +463 -0
  93. package/dist/runtime/themeComponents.js.map +1 -0
  94. package/dist/runtime/themeDecor.d.ts +73 -0
  95. package/dist/runtime/themeDecor.js +131 -0
  96. package/dist/runtime/themeDecor.js.map +1 -0
  97. package/dist/runtime/themeDoctor.d.ts +11 -0
  98. package/dist/runtime/themeDoctor.js +51 -0
  99. package/dist/runtime/themeDoctor.js.map +1 -0
  100. package/dist/runtime/themeIcons.d.ts +130 -0
  101. package/dist/runtime/themeIcons.js +263 -0
  102. package/dist/runtime/themeIcons.js.map +1 -0
  103. package/dist/runtime/themeRuntime.d.ts +100 -0
  104. package/dist/runtime/themeRuntime.js +497 -0
  105. package/dist/runtime/themeRuntime.js.map +1 -0
  106. package/dist/runtime/themeSchema.d.ts +10 -0
  107. package/dist/runtime/themeSchema.js +150 -0
  108. package/dist/runtime/themeSchema.js.map +1 -0
  109. package/dist/runtime/themeSpec.d.ts +259 -0
  110. package/dist/runtime/themeSpec.js +439 -0
  111. package/dist/runtime/themeSpec.js.map +1 -0
  112. package/dist/runtime/themeTokens.d.ts +12 -0
  113. package/dist/runtime/themeTokens.js +14 -6
  114. package/dist/runtime/themeTokens.js.map +1 -1
  115. package/dist/runtime/themeVariants.d.ts +30 -0
  116. package/dist/runtime/themeVariants.js +53 -0
  117. package/dist/runtime/themeVariants.js.map +1 -0
  118. package/dist/runtime/ui.d.ts +192 -0
  119. package/dist/runtime/ui.js +926 -0
  120. package/dist/runtime/ui.js.map +1 -0
  121. package/dist/shell/InstallDialog.d.ts +40 -0
  122. package/dist/shell/InstallDialog.js +170 -0
  123. package/dist/shell/InstallDialog.js.map +1 -0
  124. package/dist/shell/StoreView.d.ts +66 -0
  125. package/dist/shell/StoreView.js +103 -0
  126. package/dist/shell/StoreView.js.map +1 -0
  127. package/dist/shell/addressModel.js.map +1 -1
  128. package/dist/shell/chrome.js.map +1 -1
  129. package/dist/shell/deckModel.d.ts +117 -0
  130. package/dist/shell/deckModel.js +267 -0
  131. package/dist/shell/deckModel.js.map +1 -0
  132. package/dist/shell/frame/AccountSwitcher.d.ts +42 -0
  133. package/dist/shell/frame/AccountSwitcher.js +243 -0
  134. package/dist/shell/frame/AccountSwitcher.js.map +1 -0
  135. package/dist/shell/frame/AddColumnDialog.d.ts +8 -0
  136. package/dist/shell/frame/AddColumnDialog.js +81 -0
  137. package/dist/shell/frame/AddColumnDialog.js.map +1 -0
  138. package/dist/shell/frame/AppMenu.d.ts +21 -0
  139. package/dist/shell/frame/AppMenu.js +642 -0
  140. package/dist/shell/frame/AppMenu.js.map +1 -0
  141. package/dist/shell/frame/CommandPalette.d.ts +7 -0
  142. package/dist/shell/frame/CommandPalette.js +118 -0
  143. package/dist/shell/frame/CommandPalette.js.map +1 -0
  144. package/dist/shell/frame/DeckView.d.ts +13 -0
  145. package/dist/shell/frame/DeckView.js +287 -0
  146. package/dist/shell/frame/DeckView.js.map +1 -0
  147. package/dist/shell/frame/FindBar.d.ts +10 -0
  148. package/dist/shell/frame/FindBar.js +108 -0
  149. package/dist/shell/frame/FindBar.js.map +1 -0
  150. package/dist/shell/frame/MediaPanel.d.ts +8 -0
  151. package/dist/shell/frame/MediaPanel.js +76 -0
  152. package/dist/shell/frame/MediaPanel.js.map +1 -0
  153. package/dist/shell/frame/NewTabPage.d.ts +9 -0
  154. package/dist/shell/frame/NewTabPage.js +71 -0
  155. package/dist/shell/frame/NewTabPage.js.map +1 -0
  156. package/dist/shell/frame/PaneTheme.d.ts +16 -0
  157. package/dist/shell/frame/PaneTheme.js +67 -0
  158. package/dist/shell/frame/PaneTheme.js.map +1 -0
  159. package/dist/shell/frame/ReportDialog.d.ts +3 -0
  160. package/dist/shell/frame/ReportDialog.js +95 -0
  161. package/dist/shell/frame/ReportDialog.js.map +1 -0
  162. package/dist/shell/frame/Shell.d.ts +8 -0
  163. package/dist/shell/frame/Shell.js +1131 -0
  164. package/dist/shell/frame/Shell.js.map +1 -0
  165. package/dist/shell/frame/Titlebar.d.ts +16 -0
  166. package/dist/shell/frame/Titlebar.js +77 -0
  167. package/dist/shell/frame/Titlebar.js.map +1 -0
  168. package/dist/shell/frame/TitlebarExtras.d.ts +4 -0
  169. package/dist/shell/frame/TitlebarExtras.js +202 -0
  170. package/dist/shell/frame/TitlebarExtras.js.map +1 -0
  171. package/dist/shell/frame/WebPanel.d.ts +4 -0
  172. package/dist/shell/frame/WebPanel.js +182 -0
  173. package/dist/shell/frame/WebPanel.js.map +1 -0
  174. package/dist/shell/frame/accountModel.d.ts +49 -0
  175. package/dist/shell/frame/accountModel.js +67 -0
  176. package/dist/shell/frame/accountModel.js.map +1 -0
  177. package/dist/shell/frame/accountSwitcher.css +91 -0
  178. package/dist/shell/frame/appI18n.d.ts +44 -0
  179. package/dist/shell/frame/appI18n.js +64 -0
  180. package/dist/shell/frame/appI18n.js.map +1 -0
  181. package/dist/shell/frame/appMenu.css +121 -0
  182. package/dist/shell/frame/backupModel.d.ts +38 -0
  183. package/dist/shell/frame/backupModel.js +192 -0
  184. package/dist/shell/frame/backupModel.js.map +1 -0
  185. package/dist/shell/frame/boot.d.ts +8 -0
  186. package/dist/shell/frame/boot.js +35 -0
  187. package/dist/shell/frame/boot.js.map +1 -0
  188. package/dist/shell/frame/brand.d.ts +1 -0
  189. package/dist/shell/frame/brand.js +4 -0
  190. package/dist/shell/frame/brand.js.map +1 -0
  191. package/dist/shell/frame/bridge.d.ts +35 -0
  192. package/dist/shell/frame/bridge.js +70 -0
  193. package/dist/shell/frame/bridge.js.map +1 -0
  194. package/dist/shell/frame/chromeTheme.d.ts +29 -0
  195. package/dist/shell/frame/chromeTheme.js +81 -0
  196. package/dist/shell/frame/chromeTheme.js.map +1 -0
  197. package/dist/shell/frame/deck.css +209 -0
  198. package/dist/shell/frame/deckStore.d.ts +89 -0
  199. package/dist/shell/frame/deckStore.js +239 -0
  200. package/dist/shell/frame/deckStore.js.map +1 -0
  201. package/dist/shell/frame/devHost.d.ts +35 -0
  202. package/dist/shell/frame/devHost.js +80 -0
  203. package/dist/shell/frame/devHost.js.map +1 -0
  204. package/dist/shell/frame/devModel.d.ts +7 -0
  205. package/dist/shell/frame/devModel.js +17 -0
  206. package/dist/shell/frame/devModel.js.map +1 -0
  207. package/dist/shell/frame/diag.d.ts +7 -0
  208. package/dist/shell/frame/diag.js +39 -0
  209. package/dist/shell/frame/diag.js.map +1 -0
  210. package/dist/shell/frame/findBar.css +14 -0
  211. package/dist/shell/frame/frameMessages.d.ts +248 -0
  212. package/dist/shell/frame/frameMessages.js +252 -0
  213. package/dist/shell/frame/frameMessages.js.map +1 -0
  214. package/dist/shell/frame/hooks.d.ts +39 -0
  215. package/dist/shell/frame/hooks.js +97 -0
  216. package/dist/shell/frame/hooks.js.map +1 -0
  217. package/dist/shell/frame/i18n.d.ts +27 -0
  218. package/dist/shell/frame/i18n.js +66 -0
  219. package/dist/shell/frame/i18n.js.map +1 -0
  220. package/dist/shell/frame/iconPack.d.ts +11 -0
  221. package/dist/shell/frame/iconPack.js +45 -0
  222. package/dist/shell/frame/iconPack.js.map +1 -0
  223. package/dist/shell/frame/icons.d.ts +71 -0
  224. package/dist/shell/frame/icons.js +75 -0
  225. package/dist/shell/frame/icons.js.map +1 -0
  226. package/dist/shell/frame/index.d.ts +34 -0
  227. package/dist/shell/frame/index.js +43 -0
  228. package/dist/shell/frame/index.js.map +1 -0
  229. package/dist/shell/frame/language.d.ts +58 -0
  230. package/dist/shell/frame/language.js +165 -0
  231. package/dist/shell/frame/language.js.map +1 -0
  232. package/dist/shell/frame/mediaModel.d.ts +34 -0
  233. package/dist/shell/frame/mediaModel.js +53 -0
  234. package/dist/shell/frame/mediaModel.js.map +1 -0
  235. package/dist/shell/frame/menuMessages.en.json +54 -0
  236. package/dist/shell/frame/menuModel.d.ts +277 -0
  237. package/dist/shell/frame/menuModel.js +293 -0
  238. package/dist/shell/frame/menuModel.js.map +1 -0
  239. package/dist/shell/frame/paletteModel.d.ts +139 -0
  240. package/dist/shell/frame/paletteModel.js +112 -0
  241. package/dist/shell/frame/paletteModel.js.map +1 -0
  242. package/dist/shell/frame/paneTheme.css +9 -0
  243. package/dist/shell/frame/pluginCommandStore.d.ts +23 -0
  244. package/dist/shell/frame/pluginCommandStore.js +70 -0
  245. package/dist/shell/frame/pluginCommandStore.js.map +1 -0
  246. package/dist/shell/frame/reportModel.d.ts +52 -0
  247. package/dist/shell/frame/reportModel.js +105 -0
  248. package/dist/shell/frame/reportModel.js.map +1 -0
  249. package/dist/shell/frame/safeStore.d.ts +7 -0
  250. package/dist/shell/frame/safeStore.js +40 -0
  251. package/dist/shell/frame/safeStore.js.map +1 -0
  252. package/dist/shell/frame/searchInput.d.ts +2 -0
  253. package/dist/shell/frame/searchInput.js +11 -0
  254. package/dist/shell/frame/searchInput.js.map +1 -0
  255. package/dist/shell/frame/shell.css +629 -0
  256. package/dist/shell/frame/site.d.ts +206 -0
  257. package/dist/shell/frame/site.js +22 -0
  258. package/dist/shell/frame/site.js.map +1 -0
  259. package/dist/shell/frame/state.d.ts +99 -0
  260. package/dist/shell/frame/state.js +284 -0
  261. package/dist/shell/frame/state.js.map +1 -0
  262. package/dist/shell/frame/syncGate.d.ts +10 -0
  263. package/dist/shell/frame/syncGate.js +36 -0
  264. package/dist/shell/frame/syncGate.js.map +1 -0
  265. package/dist/shell/frame/syncHost.d.ts +35 -0
  266. package/dist/shell/frame/syncHost.js +85 -0
  267. package/dist/shell/frame/syncHost.js.map +1 -0
  268. package/dist/shell/frame/tabStill.d.ts +2 -0
  269. package/dist/shell/frame/tabStill.js +62 -0
  270. package/dist/shell/frame/tabStill.js.map +1 -0
  271. package/dist/shell/frame/themeScopes.d.ts +29 -0
  272. package/dist/shell/frame/themeScopes.js +61 -0
  273. package/dist/shell/frame/themeScopes.js.map +1 -0
  274. package/dist/shell/frame/themeStore.d.ts +99 -0
  275. package/dist/shell/frame/themeStore.js +252 -0
  276. package/dist/shell/frame/themeStore.js.map +1 -0
  277. package/dist/shell/frame/windowBinding.d.ts +2 -0
  278. package/dist/shell/frame/windowBinding.js +7 -0
  279. package/dist/shell/frame/windowBinding.js.map +1 -0
  280. package/dist/shell/frame/workspaceModel.d.ts +82 -0
  281. package/dist/shell/frame/workspaceModel.js +250 -0
  282. package/dist/shell/frame/workspaceModel.js.map +1 -0
  283. package/dist/shell/frame/workspaces.css +84 -0
  284. package/dist/shell/frame/workspaces.d.ts +22 -0
  285. package/dist/shell/frame/workspaces.js +125 -0
  286. package/dist/shell/frame/workspaces.js.map +1 -0
  287. package/dist/shell/frame/zoomStore.d.ts +10 -0
  288. package/dist/shell/frame/zoomStore.js +65 -0
  289. package/dist/shell/frame/zoomStore.js.map +1 -0
  290. package/dist/shell/installController.d.ts +122 -0
  291. package/dist/shell/installController.js +146 -0
  292. package/dist/shell/installController.js.map +1 -0
  293. package/dist/shell/installerMessages.d.ts +30 -0
  294. package/dist/shell/installerMessages.js +36 -0
  295. package/dist/shell/installerMessages.js.map +1 -0
  296. package/dist/shell/linkDrop.js.map +1 -1
  297. package/dist/shell/messages.d.ts +16 -0
  298. package/dist/shell/messages.js +27 -0
  299. package/dist/shell/messages.js.map +1 -0
  300. package/dist/shell/palette.js.map +1 -1
  301. package/dist/shell/paneModel.d.ts +22 -0
  302. package/dist/shell/paneModel.js +24 -1
  303. package/dist/shell/paneModel.js.map +1 -1
  304. package/dist/shell/panel/Appearance.d.ts +8 -0
  305. package/dist/shell/panel/Appearance.js +256 -0
  306. package/dist/shell/panel/Appearance.js.map +1 -0
  307. package/dist/shell/panel/BackupPanel.d.ts +5 -0
  308. package/dist/shell/panel/BackupPanel.js +198 -0
  309. package/dist/shell/panel/BackupPanel.js.map +1 -0
  310. package/dist/shell/panel/DeveloperPanel.d.ts +4 -0
  311. package/dist/shell/panel/DeveloperPanel.js +51 -0
  312. package/dist/shell/panel/DeveloperPanel.js.map +1 -0
  313. package/dist/shell/panel/FeatureToggles.d.ts +13 -0
  314. package/dist/shell/panel/FeatureToggles.js +42 -0
  315. package/dist/shell/panel/FeatureToggles.js.map +1 -0
  316. package/dist/shell/panel/Home.d.ts +3 -0
  317. package/dist/shell/panel/Home.js +23 -0
  318. package/dist/shell/panel/Home.js.map +1 -0
  319. package/dist/shell/panel/IconPackInstall.d.ts +15 -0
  320. package/dist/shell/panel/IconPackInstall.js +41 -0
  321. package/dist/shell/panel/IconPackInstall.js.map +1 -0
  322. package/dist/shell/panel/LanguageSettings.d.ts +1 -0
  323. package/dist/shell/panel/LanguageSettings.js +54 -0
  324. package/dist/shell/panel/LanguageSettings.js.map +1 -0
  325. package/dist/shell/panel/MakePanel.d.ts +3 -0
  326. package/dist/shell/panel/MakePanel.js +237 -0
  327. package/dist/shell/panel/MakePanel.js.map +1 -0
  328. package/dist/shell/panel/MarkdownDoc.d.ts +6 -0
  329. package/dist/shell/panel/MarkdownDoc.js +35 -0
  330. package/dist/shell/panel/MarkdownDoc.js.map +1 -0
  331. package/dist/shell/panel/Modes.d.ts +40 -0
  332. package/dist/shell/panel/Modes.js +270 -0
  333. package/dist/shell/panel/Modes.js.map +1 -0
  334. package/dist/shell/panel/NavIcon.d.ts +4 -0
  335. package/dist/shell/panel/NavIcon.js +6 -0
  336. package/dist/shell/panel/NavIcon.js.map +1 -0
  337. package/dist/shell/panel/Panel.d.ts +7 -0
  338. package/dist/shell/panel/Panel.js +139 -0
  339. package/dist/shell/panel/Panel.js.map +1 -0
  340. package/dist/shell/panel/PluginFeatures.d.ts +24 -0
  341. package/dist/shell/panel/PluginFeatures.js +165 -0
  342. package/dist/shell/panel/PluginFeatures.js.map +1 -0
  343. package/dist/shell/panel/Plugins.d.ts +33 -0
  344. package/dist/shell/panel/Plugins.js +112 -0
  345. package/dist/shell/panel/Plugins.js.map +1 -0
  346. package/dist/shell/panel/PowerSettings.d.ts +4 -0
  347. package/dist/shell/panel/PowerSettings.js +52 -0
  348. package/dist/shell/panel/PowerSettings.js.map +1 -0
  349. package/dist/shell/panel/Settings.d.ts +23 -0
  350. package/dist/shell/panel/Settings.js +116 -0
  351. package/dist/shell/panel/Settings.js.map +1 -0
  352. package/dist/shell/panel/ShareSetup.d.ts +8 -0
  353. package/dist/shell/panel/ShareSetup.js +130 -0
  354. package/dist/shell/panel/ShareSetup.js.map +1 -0
  355. package/dist/shell/panel/StoreSection.d.ts +6 -0
  356. package/dist/shell/panel/StoreSection.js +48 -0
  357. package/dist/shell/panel/StoreSection.js.map +1 -0
  358. package/dist/shell/panel/StringPacks.d.ts +11 -0
  359. package/dist/shell/panel/StringPacks.js +106 -0
  360. package/dist/shell/panel/StringPacks.js.map +1 -0
  361. package/dist/shell/panel/ThemeBuilder.d.ts +5 -0
  362. package/dist/shell/panel/ThemeBuilder.js +205 -0
  363. package/dist/shell/panel/ThemeBuilder.js.map +1 -0
  364. package/dist/shell/panel/backup.css +34 -0
  365. package/dist/shell/panel/builder.css +232 -0
  366. package/dist/shell/panel/builderModel.d.ts +55 -0
  367. package/dist/shell/panel/builderModel.js +95 -0
  368. package/dist/shell/panel/builderModel.js.map +1 -0
  369. package/dist/shell/panel/compare.d.ts +10 -0
  370. package/dist/shell/panel/compare.js +51 -0
  371. package/dist/shell/panel/compare.js.map +1 -0
  372. package/dist/shell/panel/controls.d.ts +135 -0
  373. package/dist/shell/panel/controls.js +213 -0
  374. package/dist/shell/panel/controls.js.map +1 -0
  375. package/dist/shell/panel/featureModel.d.ts +69 -0
  376. package/dist/shell/panel/featureModel.js +79 -0
  377. package/dist/shell/panel/featureModel.js.map +1 -0
  378. package/dist/shell/panel/fonts/FontBrowser.d.ts +10 -0
  379. package/dist/shell/panel/fonts/FontBrowser.js +189 -0
  380. package/dist/shell/panel/fonts/FontBrowser.js.map +1 -0
  381. package/dist/shell/panel/fonts/FontRoles.d.ts +20 -0
  382. package/dist/shell/panel/fonts/FontRoles.js +77 -0
  383. package/dist/shell/panel/fonts/FontRoles.js.map +1 -0
  384. package/dist/shell/panel/fonts/catalog.d.ts +37 -0
  385. package/dist/shell/panel/fonts/catalog.js +68 -0
  386. package/dist/shell/panel/fonts/catalog.js.map +1 -0
  387. package/dist/shell/panel/fonts/googleFontsCatalog.json +1 -0
  388. package/dist/shell/panel/index.d.ts +20 -0
  389. package/dist/shell/panel/index.js +34 -0
  390. package/dist/shell/panel/index.js.map +1 -0
  391. package/dist/shell/panel/languageModel.d.ts +5 -0
  392. package/dist/shell/panel/languageModel.js +7 -0
  393. package/dist/shell/panel/languageModel.js.map +1 -0
  394. package/dist/shell/panel/make.css +72 -0
  395. package/dist/shell/panel/makeModel.d.ts +32 -0
  396. package/dist/shell/panel/makeModel.js +84 -0
  397. package/dist/shell/panel/makeModel.js.map +1 -0
  398. package/dist/shell/panel/markdown.d.ts +46 -0
  399. package/dist/shell/panel/markdown.js +100 -0
  400. package/dist/shell/panel/markdown.js.map +1 -0
  401. package/dist/shell/panel/nav.d.ts +12 -0
  402. package/dist/shell/panel/nav.js +50 -0
  403. package/dist/shell/panel/nav.js.map +1 -0
  404. package/dist/shell/panel/panel.css +401 -0
  405. package/dist/shell/panel/panelMessages.d.ts +763 -0
  406. package/dist/shell/panel/panelMessages.js +767 -0
  407. package/dist/shell/panel/panelMessages.js.map +1 -0
  408. package/dist/shell/panel/plugins.css +59 -0
  409. package/dist/shell/panel/setupModel.d.ts +87 -0
  410. package/dist/shell/panel/setupModel.js +152 -0
  411. package/dist/shell/panel/setupModel.js.map +1 -0
  412. package/dist/shell/panel/site.d.ts +259 -0
  413. package/dist/shell/panel/site.js +25 -0
  414. package/dist/shell/panel/site.js.map +1 -0
  415. package/dist/shell/panel/strings.css +7 -0
  416. package/dist/shell/panel/themes.d.ts +10 -0
  417. package/dist/shell/panel/themes.js +8 -0
  418. package/dist/shell/panel/themes.js.map +1 -0
  419. package/dist/shell/profileModel.d.ts +3 -2
  420. package/dist/shell/profileModel.js +7 -5
  421. package/dist/shell/profileModel.js.map +1 -1
  422. package/dist/shell/store.css +230 -0
  423. package/dist/shell/storeMessages.d.ts +169 -0
  424. package/dist/shell/storeMessages.js +172 -0
  425. package/dist/shell/storeMessages.js.map +1 -0
  426. package/dist/shell/storeModel.d.ts +181 -0
  427. package/dist/shell/storeModel.js +133 -0
  428. package/dist/shell/storeModel.js.map +1 -0
  429. package/dist/shell/stringPacksModel.d.ts +44 -0
  430. package/dist/shell/stringPacksModel.js +94 -0
  431. package/dist/shell/stringPacksModel.js.map +1 -0
  432. package/dist/shell/updateModel.d.ts +2 -1
  433. package/dist/shell/updateModel.js +5 -4
  434. package/dist/shell/updateModel.js.map +1 -1
  435. package/dist/shell/windowControls.d.ts +4 -0
  436. package/dist/shell/windowControls.js +5 -0
  437. package/dist/shell/windowControls.js.map +1 -1
  438. package/i18n-config.schema.json +29 -0
  439. package/i18n-meta.schema.json +26 -0
  440. package/i18n.schema.json +42 -0
  441. package/icons.schema.json +646 -0
  442. package/languages.schema.json +23 -0
  443. package/locales/ar-x-fm.json +11 -0
  444. package/locales/ar.json +1281 -0
  445. package/locales/bg.json +1280 -0
  446. package/locales/bn.json +1280 -0
  447. package/locales/ca.json +1280 -0
  448. package/locales/cs.json +1280 -0
  449. package/locales/da.json +1280 -0
  450. package/locales/de.json +1280 -0
  451. package/locales/el.json +1280 -0
  452. package/locales/en-GB.json +27 -0
  453. package/locales/en.json +1280 -0
  454. package/locales/en.meta.json +51 -0
  455. package/locales/es.json +1280 -0
  456. package/locales/eu.json +1280 -0
  457. package/locales/fa.json +1281 -0
  458. package/locales/fi.json +1280 -0
  459. package/locales/fil.json +1280 -0
  460. package/locales/fr.json +1280 -0
  461. package/locales/ga.json +1280 -0
  462. package/locales/gl.json +1280 -0
  463. package/locales/gu.json +1280 -0
  464. package/locales/ha.json +1280 -0
  465. package/locales/he.json +1281 -0
  466. package/locales/hi.json +1280 -0
  467. package/locales/hr.json +1280 -0
  468. package/locales/hu.json +1279 -0
  469. package/locales/id.json +1280 -0
  470. package/locales/ig.json +1280 -0
  471. package/locales/it.json +1280 -0
  472. package/locales/ja.json +1280 -0
  473. package/locales/kn.json +1280 -0
  474. package/locales/ko.json +1280 -0
  475. package/locales/mr.json +1280 -0
  476. package/locales/ms.json +1280 -0
  477. package/locales/nb.json +1280 -0
  478. package/locales/nl.json +1280 -0
  479. package/locales/pl.json +1280 -0
  480. package/locales/pt.json +1280 -0
  481. package/locales/ro.json +1280 -0
  482. package/locales/ru.json +1280 -0
  483. package/locales/sk.json +1280 -0
  484. package/locales/sr.json +1280 -0
  485. package/locales/sv.json +1280 -0
  486. package/locales/ta.json +1280 -0
  487. package/locales/th.json +1280 -0
  488. package/locales/tr.json +1280 -0
  489. package/locales/uk.json +1280 -0
  490. package/locales/ur.json +1281 -0
  491. package/locales/vi.json +1280 -0
  492. package/locales/yo.json +1280 -0
  493. package/locales/zh-Hans.json +1280 -0
  494. package/locales/zh-Hant.json +1280 -0
  495. package/package.json +148 -6
  496. package/store-catalog.schema.json +65 -0
  497. package/theme.schema.json +4659 -0
  498. package/windows/installer.nsi +926 -0
  499. package/windows/languages/Basque.nsh +28 -0
  500. package/windows/languages/Catalan.nsh +28 -0
  501. package/windows/languages/Croatian.nsh +28 -0
  502. package/windows/languages/Czech.nsh +28 -0
  503. package/windows/languages/Danish.nsh +28 -0
  504. package/windows/languages/Finnish.nsh +28 -0
  505. package/windows/languages/Galician.nsh +28 -0
  506. package/windows/languages/Greek.nsh +28 -0
  507. package/windows/languages/Hungarian.nsh +28 -0
  508. package/windows/languages/Indonesian.nsh +28 -0
  509. package/windows/languages/Irish.nsh +28 -0
  510. package/windows/languages/Malay.nsh +28 -0
  511. package/windows/languages/Polish.nsh +28 -0
  512. package/windows/languages/Romanian.nsh +28 -0
  513. package/windows/languages/Serbian.nsh +28 -0
  514. package/windows/languages/Slovak.nsh +28 -0
  515. package/windows/languages/Thai.nsh +28 -0
@@ -0,0 +1,252 @@
1
+ // The shell's view of theming: the global theme choice, account/pane themes (scopes), installed
2
+ // Google fonts and a theme editor's live preview. The app's settings, pane menus and the chrome
3
+ // share it (they all live in the shell webview). Native code persists everything and themes the
4
+ // site tabs; this module themes the app's own window with the same documents. What a theme
5
+ // document is belongs to the app (`ThemeAdapter`); `createThemeStore(adapter)` makes the store the
6
+ // app keeps and hands to the frame (`site.themes`).
7
+ import { setChromeIconPack } from "./iconPack.js";
8
+ import { BOOT_CACHE_KEY } from "./boot.js";
9
+ import { invoke } from "./bridge.js";
10
+ import { CHROME_VAR_NAMES, chromeVars } from "./chromeTheme.js";
11
+ import { SCOPES_DEFAULT, normalizeScopes, prunePanes, themeIdFor } from "./themeScopes.js";
12
+ import { safe } from "./safeStore.js";
13
+ import { shell } from "./state.js";
14
+ const getError = (error) => error instanceof Error ? error.message : String(error);
15
+ export function createThemeStore(adapter) {
16
+ const state = { ready: false, choice: adapter.defaultChoice, scopes: SCOPES_DEFAULT, fonts: [], preview: null };
17
+ const listeners = new Set();
18
+ let snapshot = { ...state };
19
+ const emit = () => { snapshot = { ...state }; for (const listener of [...listeners])
20
+ listener(); applyChrome(); };
21
+ let loading = null;
22
+ /** Reads the persisted theme state once (every caller shares the same load). */
23
+ function loadThemes() {
24
+ loading ??= Promise.all([
25
+ adapter.load().catch(() => adapter.defaultChoice),
26
+ invoke('theme_scopes_get').then(normalizeScopes).catch(() => SCOPES_DEFAULT),
27
+ invoke('gfonts_installed').catch(() => []),
28
+ ]).then(([choice, scopes, fonts]) => {
29
+ Object.assign(state, { ready: true, choice, scopes, fonts: Array.isArray(fonts) ? fonts : [] });
30
+ committed = choice;
31
+ emit();
32
+ });
33
+ return loading;
34
+ }
35
+ /** The last choice native code acknowledged (an error reverts to it). */
36
+ let committed = null;
37
+ /** Shows `next` right away; `commit` persists it and themes every site tab (reverted on error). */
38
+ async function setChoice(next, commit = true) {
39
+ const previous = state.choice;
40
+ state.choice = next;
41
+ emit();
42
+ if (!commit)
43
+ return;
44
+ try {
45
+ await adapter.commit(next);
46
+ committed = next;
47
+ }
48
+ catch (error) {
49
+ state.choice = committed ?? previous;
50
+ emit();
51
+ throw new Error(getError(error));
52
+ }
53
+ }
54
+ async function setScopes(next) {
55
+ const previous = state.scopes;
56
+ state.scopes = normalizeScopes(next);
57
+ emit();
58
+ try {
59
+ await invoke('theme_scopes_set', { scopes: state.scopes });
60
+ }
61
+ catch (error) {
62
+ state.scopes = previous;
63
+ emit();
64
+ throw new Error(getError(error));
65
+ }
66
+ }
67
+ /** A theme editor's draft, shown in every site tab and the chrome until it is saved or closed. */
68
+ async function setPreview(theme) {
69
+ state.preview = theme;
70
+ emit();
71
+ try {
72
+ await adapter.preview(theme);
73
+ }
74
+ catch { /* Preview is best effort (browser preview). */ }
75
+ }
76
+ const themeState = () => state;
77
+ const allThemes = (choice = state.choice) => adapter.all(choice);
78
+ const knownTheme = (id, choice = state.choice) => allThemes(choice).some(theme => theme.id === id);
79
+ const themeName = (id) => allThemes().find(theme => theme.id === id)?.name ?? id;
80
+ /** The theme a tab (or pane) shows, as the chrome and the theme lists describe it. */
81
+ function tabTheme(tab) {
82
+ const found = themeIdFor(state.scopes, tab, adapter.preset(state.choice), id => knownTheme(id));
83
+ return { ...found, theme: adapter.resolve(adapter.choiceForId(state.choice, found.id)) };
84
+ }
85
+ // -------------------------------------------------------------------------------------------
86
+ // Google fonts in the shell (chrome, previews): registered from bytes like in the site's page.
87
+ const shellFonts = new Map();
88
+ function register(family, faces) {
89
+ for (const face of faces) {
90
+ const bytes = Uint8Array.from(atob(face.data), char => char.charCodeAt(0));
91
+ const [min, max] = face.weight;
92
+ const descriptors = { weight: min === max ? String(min) : `${min} ${max}`, style: 'normal', display: 'swap' };
93
+ if (face.unicodeRange)
94
+ descriptors.unicodeRange = face.unicodeRange;
95
+ const fontFace = new FontFace(family, bytes.buffer, descriptors);
96
+ document.fonts.add(fontFace);
97
+ void fontFace.load().catch(() => { });
98
+ }
99
+ }
100
+ /** Registers an installed Google font in the shell document once. */
101
+ function ensureShellFont(family) {
102
+ let pending = shellFonts.get(family);
103
+ if (!pending) {
104
+ pending = invoke('gfonts_faces', { family })
105
+ .then(result => { register(family, result.faces); return true; })
106
+ .catch(() => { shellFonts.delete(family); return false; });
107
+ shellFonts.set(family, pending);
108
+ }
109
+ return pending;
110
+ }
111
+ const previews = new Map();
112
+ let previewSeq = 0;
113
+ /**
114
+ * A text-subset preview of any Google font (a few KB, fetched natively): registers it under a
115
+ * private family name and resolves to that name, or null when it failed.
116
+ */
117
+ function previewFont(family, weights, text) {
118
+ const key = `${family}|${JSON.stringify(weights)}|${text}`;
119
+ let pending = previews.get(key);
120
+ if (!pending) {
121
+ const alias = `wbp-${++previewSeq}`;
122
+ const attempt = (tries) => invoke('gfonts_preview', { family, weights, text })
123
+ .then(faces => { register(alias, faces); return alias; })
124
+ .catch(error => {
125
+ // Six previews at most are in flight natively; the list retries shortly.
126
+ if (tries > 0 && /busy/i.test(getError(error)))
127
+ return new Promise(done => setTimeout(() => done(attempt(tries - 1)), 250 + Math.random() * 400));
128
+ previews.delete(key);
129
+ return null;
130
+ });
131
+ pending = attempt(12);
132
+ previews.set(key, pending);
133
+ }
134
+ return pending;
135
+ }
136
+ async function installFont(family, weights) {
137
+ const font = await invoke('gfonts_install', { family, weights });
138
+ state.fonts = [...state.fonts.filter(item => item.family !== family), font].sort((a, b) => a.family.localeCompare(b.family));
139
+ shellFonts.delete(family);
140
+ emit();
141
+ return font;
142
+ }
143
+ async function removeFont(family) {
144
+ await invoke('gfonts_remove', { family });
145
+ state.fonts = state.fonts.filter(item => item.family !== family);
146
+ emit();
147
+ }
148
+ const isInstalled = (family) => state.fonts.some(font => font.family === family);
149
+ /** Google families a theme needs that are not downloaded yet. */
150
+ const missingFonts = (theme) => adapter.googleFonts(theme).filter(family => !isInstalled(family));
151
+ // -------------------------------------------------------------------------------------------
152
+ // Chrome
153
+ function setVars(element, vars) {
154
+ for (const name of CHROME_VAR_NAMES)
155
+ if (!(name in vars))
156
+ element.style.removeProperty(name);
157
+ for (const [name, value] of Object.entries(vars))
158
+ element.style.setProperty(name, value);
159
+ }
160
+ function chromeFontsFor(theme) {
161
+ for (const family of adapter.googleFonts(theme, ['chrome', 'mono']))
162
+ if (isInstalled(family))
163
+ void ensureShellFont(family);
164
+ }
165
+ /** The chrome follows the global theme (or the editor's draft); panes with their own theme follow theirs. */
166
+ function applyChrome() {
167
+ if (typeof document === 'undefined')
168
+ return;
169
+ // Safe mode: the frame's own look, whatever the theme (a theme may be what broke the chrome). The
170
+ // first-frame cache is left alone, so the next normal start paints the owner's theme again.
171
+ if (safe.active) {
172
+ setVars(document.documentElement, {});
173
+ syncGroups();
174
+ return;
175
+ }
176
+ if (!state.ready)
177
+ return;
178
+ const own = state.scopes.chrome === 'own';
179
+ const global = state.preview ?? adapter.resolve(state.choice);
180
+ chromeFontsFor(global);
181
+ const vars = chromeVars(adapter.chrome(global), own);
182
+ setVars(document.documentElement, vars);
183
+ try {
184
+ setChromeIconPack(own ? null : adapter.iconPack?.(global, state.choice) ?? null);
185
+ }
186
+ catch {
187
+ setChromeIconPack(null);
188
+ }
189
+ // The next start paints these from its first frame (boot.ts); an editor's draft is not kept.
190
+ if (!state.preview) {
191
+ try {
192
+ localStorage.setItem(BOOT_CACHE_KEY, JSON.stringify(vars));
193
+ }
194
+ catch { /* Best effort. */ }
195
+ }
196
+ syncGroups();
197
+ }
198
+ let dock = null;
199
+ /** Pane chrome: a dock group whose active tab shows another theme than the global one gets that theme. */
200
+ function syncGroups() {
201
+ const api = dock ?? shell.api;
202
+ if (!api)
203
+ return;
204
+ const own = state.scopes.chrome === 'own';
205
+ for (const group of api.groups) {
206
+ const params = group.activePanel?.params;
207
+ const tab = params && (params.kind === 'web' || params.kind === 'start') ? { id: params.kind === 'web' ? group.activePanel.id : undefined, profile: params.profile ?? 'default' } : null;
208
+ const scoped = !own && !safe.active && !state.preview && tab ? tabTheme(tab) : null;
209
+ const element = group.element;
210
+ if (scoped && scoped.source !== 'global') {
211
+ chromeFontsFor(scoped.theme);
212
+ element.classList.add('wb-pane-theme');
213
+ setVars(element, chromeVars(adapter.chrome(scoped.theme)));
214
+ element.dataset.wbTheme = scoped.id;
215
+ }
216
+ else if (element.classList.contains('wb-pane-theme')) {
217
+ element.classList.remove('wb-pane-theme');
218
+ setVars(element, {});
219
+ delete element.dataset.wbTheme;
220
+ }
221
+ }
222
+ }
223
+ // Safe mode switched: the chrome drops (or takes back) the theme at once.
224
+ if (typeof window !== 'undefined')
225
+ window.addEventListener('bt-safe', applyChrome);
226
+ /** Shell.tsx hands over the dock once it exists: pane chrome follows focus and layout changes. */
227
+ function attachDock(api) {
228
+ dock = api;
229
+ const sync = () => requestAnimationFrame(syncGroups);
230
+ api.onDidActivePanelChange(sync);
231
+ api.onDidLayoutChange(sync);
232
+ api.onDidAddPanel(sync);
233
+ api.onDidRemovePanel(() => {
234
+ sync();
235
+ // A closed pane's theme goes with it.
236
+ const open = api.panels.map(panel => panel.id);
237
+ const pruned = prunePanes(state.scopes, open);
238
+ if (pruned !== state.scopes && !shell.restoring)
239
+ void setScopes(pruned).catch(() => { });
240
+ });
241
+ window.addEventListener('bt-profiles', sync);
242
+ void loadThemes().then(sync);
243
+ }
244
+ /** For `useThemeState` (hooks.ts): subscribe, and the current snapshot. */
245
+ const subscribe = (listener) => { listeners.add(listener); return () => { listeners.delete(listener); }; };
246
+ const current = () => snapshot;
247
+ return {
248
+ adapter, loadThemes, setChoice, setScopes, setPreview, themeState, allThemes, knownTheme, themeName, tabTheme,
249
+ ensureShellFont, previewFont, installFont, removeFont, isInstalled, missingFonts, attachDock, subscribe, current,
250
+ };
251
+ }
252
+ //# sourceMappingURL=themeStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"themeStore.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/themeStore.ts"],"names":[],"mappings":"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","sourcesContent":["// The shell's view of theming: the global theme choice, account/pane themes (scopes), installed\n// Google fonts and a theme editor's live preview. The app's settings, pane menus and the chrome\n// share it (they all live in the shell webview). Native code persists everything and themes the\n// site tabs; this module themes the app's own window with the same documents. What a theme\n// document is belongs to the app (`ThemeAdapter`); `createThemeStore(adapter)` makes the store the\n// app keeps and hands to the frame (`site.themes`).\n\nimport type { IconPack } from '../../../runtime/src/themeIcons.ts';\nimport { setChromeIconPack } from './iconPack.tsx';\nimport type { DockviewApi } from 'dockview';\nimport { BOOT_CACHE_KEY } from './boot.ts';\nimport { invoke } from './bridge.ts';\nimport { CHROME_VAR_NAMES, chromeVars, type ChromeTheme } from './chromeTheme.ts';\nimport { SCOPES_DEFAULT, normalizeScopes, prunePanes, themeIdFor, type ScopeSource, type ThemeScopes } from './themeScopes.ts';\nimport { safe } from './safeStore.ts';\nimport { shell, type TabParams } from './state.ts';\n\nexport type Weights = { kind: 'range'; min: number; max: number } | { kind: 'list'; values: number[] };\nexport type InstalledFont = { family: string; weights: Weights; bytes: number; faces: number; installedAt: string };\ntype FaceData = { weight: [number, number]; unicodeRange: string | null; data: string };\n\n/** A theme document as the frame needs it: an id and a name (the rest is the app's). */\nexport type ThemeDoc = { id: string; name: string };\n\n/** What the app's themes are and how native code stores them. */\nexport type ThemeAdapter<Choice = unknown, Spec extends ThemeDoc = ThemeDoc> = {\n /** The choice before anything is read (and when reading fails). */\n defaultChoice: Choice;\n /** Reads the persisted global choice (normalized). */\n load(): Promise<Choice>;\n /** Persists `choice` and themes every site tab (throws native code's error). */\n commit(choice: Choice): Promise<void>;\n /** Shows `spec` (a draft) in every site tab until it is saved or closed; null ends it. */\n preview(spec: Spec | null): Promise<void>;\n /** The theme document a choice shows (its customizations applied). */\n resolve(choice: Choice): Spec;\n /** The chosen theme's id. */\n preset(choice: Choice): string;\n /** The choice a theme id stands for: the global choice itself, or that theme without customizations. */\n choiceForId(choice: Choice, id: string): Choice;\n /** Every theme that can be picked: built-in ones and the choice's imported ones. */\n all(choice: Choice): Spec[];\n /** Google font families a theme uses (in `roles` only, when given). */\n googleFonts(spec: Spec, roles?: readonly string[]): string[];\n /** The chrome's colors and fonts for a theme. */\n chrome(spec: Spec): ChromeTheme;\n /** The icon pack a theme suggests for the chrome (theme engine v2); absent: the frame's own glyphs. */\n iconPack?(spec: Spec, choice?: Choice): IconPack | null;\n /** Three swatch colors for menus (page, text, accent, on the theme's surface and border). */\n dots(spec: Spec): { page: string; bg: string; border: string; text: string; accent: string };\n};\n\nexport type ThemeState<Choice, Spec> = { ready: boolean; choice: Choice; scopes: ThemeScopes; fonts: InstalledFont[]; preview: Spec | null };\n\nconst getError = (error: unknown) => error instanceof Error ? error.message : String(error);\n\nexport type ThemeStore<Choice = unknown, Spec extends ThemeDoc = ThemeDoc> = ReturnType<typeof createThemeStore<Choice, Spec>>;\n\nexport function createThemeStore<Choice, Spec extends ThemeDoc>(adapter: ThemeAdapter<Choice, Spec>) {\n const state: ThemeState<Choice, Spec> = { ready: false, choice: adapter.defaultChoice, scopes: SCOPES_DEFAULT, fonts: [], preview: null };\n const listeners = new Set<() => void>();\n let snapshot = { ...state };\n const emit = () => { snapshot = { ...state }; for (const listener of [...listeners]) listener(); applyChrome(); };\n\n let loading: Promise<void> | null = null;\n /** Reads the persisted theme state once (every caller shares the same load). */\n function loadThemes(): Promise<void> {\n loading ??= Promise.all([\n adapter.load().catch(() => adapter.defaultChoice),\n invoke<unknown>('theme_scopes_get').then(normalizeScopes).catch(() => SCOPES_DEFAULT),\n invoke<InstalledFont[]>('gfonts_installed').catch(() => [] as InstalledFont[]),\n ]).then(([choice, scopes, fonts]) => {\n Object.assign(state, { ready: true, choice, scopes, fonts: Array.isArray(fonts) ? fonts : [] });\n committed = choice;\n emit();\n });\n return loading;\n }\n\n /** The last choice native code acknowledged (an error reverts to it). */\n let committed: Choice | null = null;\n /** Shows `next` right away; `commit` persists it and themes every site tab (reverted on error). */\n async function setChoice(next: Choice, commit = true): Promise<void> {\n const previous = state.choice;\n state.choice = next;\n emit();\n if (!commit) return;\n try { await adapter.commit(next); committed = next; }\n catch (error) { state.choice = committed ?? previous; emit(); throw new Error(getError(error)); }\n }\n async function setScopes(next: ThemeScopes): Promise<void> {\n const previous = state.scopes;\n state.scopes = normalizeScopes(next);\n emit();\n try { await invoke('theme_scopes_set', { scopes: state.scopes }); }\n catch (error) { state.scopes = previous; emit(); throw new Error(getError(error)); }\n }\n\n /** A theme editor's draft, shown in every site tab and the chrome until it is saved or closed. */\n async function setPreview(theme: Spec | null): Promise<void> {\n state.preview = theme;\n emit();\n try { await adapter.preview(theme); } catch { /* Preview is best effort (browser preview). */ }\n }\n\n const themeState = () => state;\n const allThemes = (choice: Choice = state.choice) => adapter.all(choice);\n const knownTheme = (id: string, choice: Choice = state.choice) => allThemes(choice).some(theme => theme.id === id);\n const themeName = (id: string) => allThemes().find(theme => theme.id === id)?.name ?? id;\n\n /** The theme a tab (or pane) shows, as the chrome and the theme lists describe it. */\n function tabTheme(tab: { id?: string; profile?: string }): { id: string; source: ScopeSource; theme: Spec } {\n const found = themeIdFor(state.scopes, tab, adapter.preset(state.choice), id => knownTheme(id));\n return { ...found, theme: adapter.resolve(adapter.choiceForId(state.choice, found.id)) };\n }\n\n // -------------------------------------------------------------------------------------------\n // Google fonts in the shell (chrome, previews): registered from bytes like in the site's page.\n\n const shellFonts = new Map<string, Promise<boolean>>();\n function register(family: string, faces: FaceData[]) {\n for (const face of faces) {\n const bytes = Uint8Array.from(atob(face.data), char => char.charCodeAt(0));\n const [min, max] = face.weight;\n const descriptors: FontFaceDescriptors = { weight: min === max ? String(min) : `${min} ${max}`, style: 'normal', display: 'swap' };\n if (face.unicodeRange) descriptors.unicodeRange = face.unicodeRange;\n const fontFace = new FontFace(family, bytes.buffer, descriptors);\n document.fonts.add(fontFace);\n void fontFace.load().catch(() => {});\n }\n }\n /** Registers an installed Google font in the shell document once. */\n function ensureShellFont(family: string): Promise<boolean> {\n let pending = shellFonts.get(family);\n if (!pending) {\n pending = invoke<{ faces: FaceData[] }>('gfonts_faces', { family })\n .then(result => { register(family, result.faces); return true; })\n .catch(() => { shellFonts.delete(family); return false; });\n shellFonts.set(family, pending);\n }\n return pending;\n }\n\n const previews = new Map<string, Promise<string | null>>();\n let previewSeq = 0;\n /**\n * A text-subset preview of any Google font (a few KB, fetched natively): registers it under a\n * private family name and resolves to that name, or null when it failed.\n */\n function previewFont(family: string, weights: Weights, text: string): Promise<string | null> {\n const key = `${family}|${JSON.stringify(weights)}|${text}`;\n let pending = previews.get(key);\n if (!pending) {\n const alias = `wbp-${++previewSeq}`;\n const attempt = (tries: number): Promise<string | null> => invoke<FaceData[]>('gfonts_preview', { family, weights, text })\n .then(faces => { register(alias, faces); return alias; })\n .catch(error => {\n // Six previews at most are in flight natively; the list retries shortly.\n if (tries > 0 && /busy/i.test(getError(error))) return new Promise<string | null>(done => setTimeout(() => done(attempt(tries - 1)), 250 + Math.random() * 400));\n previews.delete(key);\n return null;\n });\n pending = attempt(12);\n previews.set(key, pending);\n }\n return pending;\n }\n\n async function installFont(family: string, weights: Weights): Promise<InstalledFont> {\n const font = await invoke<InstalledFont>('gfonts_install', { family, weights });\n state.fonts = [...state.fonts.filter(item => item.family !== family), font].sort((a, b) => a.family.localeCompare(b.family));\n shellFonts.delete(family);\n emit();\n return font;\n }\n\n async function removeFont(family: string): Promise<void> {\n await invoke('gfonts_remove', { family });\n state.fonts = state.fonts.filter(item => item.family !== family);\n emit();\n }\n\n const isInstalled = (family: string) => state.fonts.some(font => font.family === family);\n /** Google families a theme needs that are not downloaded yet. */\n const missingFonts = (theme: Spec) => adapter.googleFonts(theme).filter(family => !isInstalled(family));\n\n // -------------------------------------------------------------------------------------------\n // Chrome\n\n function setVars(element: HTMLElement, vars: Record<string, string>) {\n for (const name of CHROME_VAR_NAMES) if (!(name in vars)) element.style.removeProperty(name);\n for (const [name, value] of Object.entries(vars)) element.style.setProperty(name, value);\n }\n\n function chromeFontsFor(theme: Spec) {\n for (const family of adapter.googleFonts(theme, ['chrome', 'mono'])) if (isInstalled(family)) void ensureShellFont(family);\n }\n\n /** The chrome follows the global theme (or the editor's draft); panes with their own theme follow theirs. */\n function applyChrome() {\n if (typeof document === 'undefined') return;\n // Safe mode: the frame's own look, whatever the theme (a theme may be what broke the chrome). The\n // first-frame cache is left alone, so the next normal start paints the owner's theme again.\n if (safe.active) { setVars(document.documentElement, {}); syncGroups(); return; }\n if (!state.ready) return;\n const own = state.scopes.chrome === 'own';\n const global = state.preview ?? adapter.resolve(state.choice);\n chromeFontsFor(global);\n const vars = chromeVars(adapter.chrome(global), own);\n setVars(document.documentElement, vars);\n try { setChromeIconPack(own ? null : adapter.iconPack?.(global, state.choice) ?? null); } catch { setChromeIconPack(null); }\n // The next start paints these from its first frame (boot.ts); an editor's draft is not kept.\n if (!state.preview) { try { localStorage.setItem(BOOT_CACHE_KEY, JSON.stringify(vars)); } catch { /* Best effort. */ } }\n syncGroups();\n }\n\n let dock: DockviewApi | null = null;\n /** Pane chrome: a dock group whose active tab shows another theme than the global one gets that theme. */\n function syncGroups() {\n const api = dock ?? shell.api;\n if (!api) return;\n const own = state.scopes.chrome === 'own';\n for (const group of api.groups) {\n const params = group.activePanel?.params as TabParams | undefined;\n const tab = params && (params.kind === 'web' || params.kind === 'start') ? { id: params.kind === 'web' ? group.activePanel!.id : undefined, profile: params.profile ?? 'default' } : null;\n const scoped = !own && !safe.active && !state.preview && tab ? tabTheme(tab) : null;\n const element = group.element;\n if (scoped && scoped.source !== 'global') {\n chromeFontsFor(scoped.theme);\n element.classList.add('wb-pane-theme');\n setVars(element, chromeVars(adapter.chrome(scoped.theme)));\n element.dataset.wbTheme = scoped.id;\n } else if (element.classList.contains('wb-pane-theme')) {\n element.classList.remove('wb-pane-theme');\n setVars(element, {});\n delete element.dataset.wbTheme;\n }\n }\n }\n\n // Safe mode switched: the chrome drops (or takes back) the theme at once.\n if (typeof window !== 'undefined') window.addEventListener('bt-safe', applyChrome);\n\n /** Shell.tsx hands over the dock once it exists: pane chrome follows focus and layout changes. */\n function attachDock(api: DockviewApi) {\n dock = api;\n const sync = () => requestAnimationFrame(syncGroups);\n api.onDidActivePanelChange(sync);\n api.onDidLayoutChange(sync);\n api.onDidAddPanel(sync);\n api.onDidRemovePanel(() => {\n sync();\n // A closed pane's theme goes with it.\n const open = api.panels.map(panel => panel.id);\n const pruned = prunePanes(state.scopes, open);\n if (pruned !== state.scopes && !shell.restoring) void setScopes(pruned).catch(() => {});\n });\n window.addEventListener('bt-profiles', sync);\n void loadThemes().then(sync);\n }\n\n /** For `useThemeState` (hooks.ts): subscribe, and the current snapshot. */\n const subscribe = (listener: () => void) => { listeners.add(listener); return () => { listeners.delete(listener); }; };\n const current = () => snapshot;\n\n return {\n adapter, loadThemes, setChoice, setScopes, setPreview, themeState, allThemes, knownTheme, themeName, tabTheme,\n ensureShellFont, previewFont, installFont, removeFont, isInstalled, missingFonts, attachDock, subscribe, current,\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { frameless, isTauri, os, type ResizeDirection } from '../windowControls.ts';
2
+ export declare const minimize: () => Promise<void>, toggleMaximize: () => Promise<void>, close: () => Promise<void>, startResize: (direction: import("./windowBinding.ts").ResizeDirection) => Promise<void>, startDrag: () => void, onMaximizedChange: (cb: (maximized: boolean) => void) => Promise<() => void>, systemMenu: (x: number, y: number) => Promise<unknown>;
@@ -0,0 +1,7 @@
1
+ // The frame's window controls (custom titlebar, grips, caption buttons), bound to the app's Tauri
2
+ // API as handed to createShell.
3
+ import { createWindowControls } from "../windowControls.js";
4
+ import { currentWindow, invoke } from "./bridge.js";
5
+ export { frameless, isTauri, os } from "../windowControls.js";
6
+ export const { minimize, toggleMaximize, close, startResize, startDrag, onMaximizedChange, systemMenu } = createWindowControls((command, args) => invoke(command, args), currentWindow);
7
+ //# sourceMappingURL=windowBinding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowBinding.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/windowBinding.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,gCAAgC;AAEhC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAwB,MAAM,sBAAsB,CAAC;AAEpF,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,UAAU,EAAE,GACrG,oBAAoB,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC","sourcesContent":["// The frame's window controls (custom titlebar, grips, caption buttons), bound to the app's Tauri\n// API as handed to createShell.\n\nimport { createWindowControls } from '../windowControls.ts';\nimport { currentWindow, invoke } from './bridge.ts';\n\nexport { frameless, isTauri, os, type ResizeDirection } from '../windowControls.ts';\n\nexport const { minimize, toggleMaximize, close, startResize, startDrag, onMaximizedChange, systemMenu } =\n createWindowControls((command, args) => invoke(command, args), currentWindow);\n"]}
@@ -0,0 +1,82 @@
1
+ export declare const WORKSPACE_LIMITS: Readonly<{
2
+ /** Saved workspaces. */
3
+ count: 20;
4
+ name: 60;
5
+ /** Tabs in one workspace. */
6
+ tabs: 64;
7
+ /** Serialized size of one workspace (JSON characters). */
8
+ bytes: number;
9
+ url: 4096;
10
+ title: 300;
11
+ }>;
12
+ export type WorkspaceTab = {
13
+ kind: 'web' | 'panel' | 'start' | 'deck';
14
+ url?: string;
15
+ profile?: string;
16
+ title?: string;
17
+ };
18
+ export type Workspace = {
19
+ id: string;
20
+ name: string;
21
+ savedAt: string;
22
+ /** dockview's `SerializedDockview`, reduced (see `captureWorkspace`). */
23
+ layout: SerializedLayout;
24
+ /** Pane themes of this workspace's tabs: tab id (in `layout`) → theme id. */
25
+ paneThemes: Record<string, string>;
26
+ /** Decks the workspace shows (Power User Mode), so a deck deleted since can come back. */
27
+ decks?: unknown[];
28
+ };
29
+ export type WorkspaceStore = {
30
+ version: 1;
31
+ default: string | null;
32
+ items: Workspace[];
33
+ };
34
+ export declare const EMPTY_WORKSPACES: WorkspaceStore;
35
+ type Json = Record<string, unknown>;
36
+ export type SerializedLayout = {
37
+ grid: Json;
38
+ panels: Record<string, Json>;
39
+ activeGroup?: string;
40
+ floatingGroups?: unknown[];
41
+ popoutGroups?: unknown[];
42
+ };
43
+ export declare function httpUrl(value: unknown): string | null;
44
+ export declare function cleanName(value: unknown): string;
45
+ /** A slug for a new workspace id, unique among `taken`. */
46
+ export declare function workspaceId(name: string, taken: Iterable<string>): string;
47
+ export type CaptureInput = {
48
+ id: string;
49
+ name: string;
50
+ layout: unknown;
51
+ /** The pane theme map (`ThemeScopes.panes`); only this layout's tabs are kept. */
52
+ paneThemes?: Record<string, string>;
53
+ decks?: Array<{
54
+ id: string;
55
+ }>;
56
+ now?: Date;
57
+ };
58
+ /** Makes a workspace from the live dockview layout. Throws when there is nothing to keep or it is too large. */
59
+ export declare function captureWorkspace(input: CaptureInput): Workspace;
60
+ /** Tabs of a workspace in layout order (for menus: "3 tabs · x.com/home, …"). */
61
+ export declare function workspaceTabs(workspace: Workspace): WorkspaceTab[];
62
+ export type RestorePlan = {
63
+ layout: SerializedLayout;
64
+ /** Pane themes for the restored tab ids. */
65
+ paneThemes: Record<string, string>;
66
+ /** Tab id in the workspace → id it gets now. */
67
+ ids: Record<string, string>;
68
+ };
69
+ /**
70
+ * The layout to hand dockview's `fromJSON`: web and new-tab pages get fresh ids from `newId`
71
+ * (a live tab never keeps its webview across a switch), deck and wayBetter tabs keep theirs.
72
+ * `profileKnown` drops accounts that no longer exist (the tab opens in the default account).
73
+ */
74
+ export declare function planRestore(workspace: Workspace, newId: () => string, profileKnown?: (id: string) => boolean): RestorePlan;
75
+ /** Parses what native code returned; anything malformed is dropped, never thrown. */
76
+ export declare function normalizeWorkspaces(value: unknown): WorkspaceStore;
77
+ /** Adds or replaces (same id) a workspace; the list stays bounded. */
78
+ export declare function upsertWorkspace(store: WorkspaceStore, workspace: Workspace): WorkspaceStore;
79
+ export declare function removeWorkspace(store: WorkspaceStore, id: string): WorkspaceStore;
80
+ export declare function renameWorkspace(store: WorkspaceStore, id: string, name: string): WorkspaceStore;
81
+ export declare function setDefaultWorkspace(store: WorkspaceStore, id: string | null): WorkspaceStore;
82
+ export {};
@@ -0,0 +1,250 @@
1
+ // Workspaces: named snapshots of the tab/pane/deck layout (each tab's URL, account profile and pane
2
+ // theme), restored with one click, switched from Ctrl+K and the titlebar menu, one optionally
3
+ // opened on start. Pure (no Tauri/DOM imports) so it is unit-tested under node. Stored natively
4
+ // (`workspaces_get` / `workspaces_set`; waybetter-host `workspaces` re-checks the same bounds).
5
+ //
6
+ // A workspace keeps dockview's own serialized layout, reduced to what reopening needs: panels of
7
+ // the kinds the shell knows, their params without transient state (loading, nonces), http(s)
8
+ // URLs only. Restoring gives every web/new-tab page a fresh id (so it opens as a new webview and
9
+ // never inherits a live tab's state); deck tabs and the app's panel keep their fixed ids.
10
+ import { t } from "./i18n.js";
11
+ export const WORKSPACE_LIMITS = Object.freeze({
12
+ /** Saved workspaces. */
13
+ count: 20,
14
+ name: 60,
15
+ /** Tabs in one workspace. */
16
+ tabs: 64,
17
+ /** Serialized size of one workspace (JSON characters). */
18
+ bytes: 256 * 1024,
19
+ url: 4096,
20
+ title: 300,
21
+ });
22
+ export const EMPTY_WORKSPACES = { version: 1, default: null, items: [] };
23
+ const KINDS = new Set(['web', 'panel', 'start', 'deck']);
24
+ /** Params each kind keeps; everything else (loading, nonce, favicon, besideOf, ...) is dropped. */
25
+ const KEEP = {
26
+ web: ['kind', 'url', 'profile', 'title', 'pinned'],
27
+ panel: ['kind', 'section', 'pinned'],
28
+ start: ['kind', 'profile', 'pinned'],
29
+ deck: ['kind', 'deckId', 'pinned'],
30
+ };
31
+ const ID = /^[A-Za-z0-9_-]{1,64}$/;
32
+ const THEME_ID = /^[a-z0-9-]{1,40}$/;
33
+ const WORKSPACE_ID = /^[a-z0-9-]{1,40}$/;
34
+ const isObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
35
+ export function httpUrl(value) {
36
+ if (typeof value !== 'string' || value.length > WORKSPACE_LIMITS.url)
37
+ return null;
38
+ try {
39
+ const url = new URL(value);
40
+ return url.protocol === 'https:' || url.protocol === 'http:' ? url.href : null;
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ export function cleanName(value) {
47
+ // eslint-disable-next-line no-control-regex
48
+ return typeof value === 'string' ? value.replace(/[\u0000-\u001f\u007f]+/g, ' ').replace(/\s+/g, ' ').trim().slice(0, WORKSPACE_LIMITS.name) : '';
49
+ }
50
+ /** A slug for a new workspace id, unique among `taken`. */
51
+ export function workspaceId(name, taken) {
52
+ const used = new Set(taken);
53
+ const base = cleanName(name).toLowerCase().normalize('NFKD').replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 32) || 'workspace';
54
+ let id = base;
55
+ for (let n = 2; used.has(id); n += 1)
56
+ id = `${base}-${n}`;
57
+ return id;
58
+ }
59
+ /** A panel's params reduced to what reopening needs, or null when the panel cannot be kept. */
60
+ function cleanParams(params) {
61
+ if (!isObject(params) || typeof params.kind !== 'string' || !KINDS.has(params.kind))
62
+ return null;
63
+ const out = {};
64
+ for (const key of KEEP[params.kind]) {
65
+ const value = params[key];
66
+ if (value === undefined || value === null)
67
+ continue;
68
+ if (key === 'url') {
69
+ const url = httpUrl(value);
70
+ if (!url)
71
+ return null;
72
+ out.url = url;
73
+ }
74
+ else if (key === 'pinned') {
75
+ if (value === true)
76
+ out.pinned = true;
77
+ }
78
+ else if (key === 'title') {
79
+ if (typeof value === 'string')
80
+ out.title = value.slice(0, WORKSPACE_LIMITS.title);
81
+ }
82
+ else if (typeof value === 'string' && value.length <= 64) {
83
+ out[key] = value;
84
+ }
85
+ }
86
+ if (params.kind === 'web' && !out.url)
87
+ return null;
88
+ if (params.kind === 'deck' && typeof out.deckId !== 'string')
89
+ return null;
90
+ return out;
91
+ }
92
+ /** Visits every group's `views`/`activeView` in the grid and in floating/popout groups. */
93
+ function mapGroups(value, fn) {
94
+ if (Array.isArray(value)) {
95
+ for (const item of value)
96
+ mapGroups(item, fn);
97
+ return;
98
+ }
99
+ if (!isObject(value))
100
+ return;
101
+ if (Array.isArray(value.views))
102
+ fn(value);
103
+ for (const [key, child] of Object.entries(value))
104
+ if (key !== 'views')
105
+ mapGroups(child, fn);
106
+ }
107
+ const clone = (value) => JSON.parse(JSON.stringify(value));
108
+ /** Drops views whose panel is gone; returns the tab ids still referenced. */
109
+ function pruneViews(layout) {
110
+ const referenced = new Set();
111
+ mapGroups([layout.grid, layout.floatingGroups, layout.popoutGroups], group => {
112
+ const views = group.views.filter((id) => typeof id === 'string' && id in layout.panels);
113
+ group.views = views;
114
+ if (typeof group.activeView === 'string' && !views.includes(group.activeView))
115
+ group.activeView = views[0];
116
+ for (const id of views)
117
+ referenced.add(id);
118
+ });
119
+ return referenced;
120
+ }
121
+ /** Makes a workspace from the live dockview layout. Throws when there is nothing to keep or it is too large. */
122
+ export function captureWorkspace(input) {
123
+ const name = cleanName(input.name);
124
+ if (!name)
125
+ throw new Error('A workspace needs a name.');
126
+ if (!WORKSPACE_ID.test(input.id))
127
+ throw new Error(t('wb.ws.err.id'));
128
+ const raw = input.layout;
129
+ if (!isObject(raw) || !isObject(raw.grid) || !isObject(raw.panels))
130
+ throw new Error(t('wb.ws.err.noLayout'));
131
+ const layout = clone(raw);
132
+ const panels = {};
133
+ for (const [id, panel] of Object.entries(layout.panels)) {
134
+ if (!ID.test(id) || !isObject(panel))
135
+ continue;
136
+ const params = cleanParams(panel.params);
137
+ if (!params)
138
+ continue;
139
+ const title = typeof panel.title === 'string' ? panel.title.slice(0, WORKSPACE_LIMITS.title) : undefined;
140
+ panels[id] = { id, contentComponent: panel.contentComponent, params, ...(title ? { title } : {}) };
141
+ }
142
+ layout.panels = panels;
143
+ const kept = pruneViews(layout);
144
+ for (const id of Object.keys(layout.panels))
145
+ if (!kept.has(id))
146
+ delete layout.panels[id];
147
+ const count = Object.keys(layout.panels).length;
148
+ if (!count)
149
+ throw new Error(t('wb.ws.err.noTabs'));
150
+ if (count > WORKSPACE_LIMITS.tabs)
151
+ throw new Error(`A workspace holds at most ${WORKSPACE_LIMITS.tabs} tabs.`);
152
+ const paneThemes = {};
153
+ for (const [tab, theme] of Object.entries(input.paneThemes ?? {})) {
154
+ if (tab in layout.panels && typeof theme === 'string' && THEME_ID.test(theme))
155
+ paneThemes[tab] = theme;
156
+ }
157
+ const deckIds = new Set(Object.values(layout.panels).map(panel => panel.params.deckId).filter((id) => typeof id === 'string'));
158
+ const decks = (input.decks ?? []).filter(deck => deckIds.has(deck.id));
159
+ const workspace = {
160
+ id: input.id,
161
+ name,
162
+ savedAt: (input.now ?? new Date()).toISOString(),
163
+ layout,
164
+ paneThemes,
165
+ ...(decks.length ? { decks: clone(decks) } : {}),
166
+ };
167
+ if (JSON.stringify(workspace).length > WORKSPACE_LIMITS.bytes)
168
+ throw new Error(t('wb.ws.err.tooLarge'));
169
+ return workspace;
170
+ }
171
+ /** Tabs of a workspace in layout order (for menus: "3 tabs · x.com/home, …"). */
172
+ export function workspaceTabs(workspace) {
173
+ const order = [];
174
+ mapGroups([workspace.layout.grid, workspace.layout.floatingGroups], group => { for (const id of group.views)
175
+ if (!order.includes(id))
176
+ order.push(id); });
177
+ return order.map(id => workspace.layout.panels[id]?.params).filter((tab) => !!tab);
178
+ }
179
+ /**
180
+ * The layout to hand dockview's `fromJSON`: web and new-tab pages get fresh ids from `newId`
181
+ * (a live tab never keeps its webview across a switch), deck and wayBetter tabs keep theirs.
182
+ * `profileKnown` drops accounts that no longer exist (the tab opens in the default account).
183
+ */
184
+ export function planRestore(workspace, newId, profileKnown = () => true) {
185
+ const layout = clone(workspace.layout);
186
+ const ids = {};
187
+ const panels = {};
188
+ for (const [id, panel] of Object.entries(layout.panels)) {
189
+ const params = cleanParams(panel.params);
190
+ if (!params)
191
+ continue;
192
+ if (typeof params.profile === 'string' && !profileKnown(params.profile))
193
+ delete params.profile;
194
+ const fresh = params.kind === 'web' || params.kind === 'start' ? newId() : id;
195
+ ids[id] = fresh;
196
+ panels[fresh] = { ...panel, id: fresh, params };
197
+ }
198
+ layout.panels = panels;
199
+ mapGroups([layout.grid, layout.floatingGroups, layout.popoutGroups], group => {
200
+ group.views = group.views.map(id => (typeof id === 'string' ? ids[id] : undefined)).filter((id) => !!id);
201
+ if (typeof group.activeView === 'string')
202
+ group.activeView = ids[group.activeView] ?? group.views[0];
203
+ });
204
+ pruneViews(layout);
205
+ const paneThemes = {};
206
+ for (const [tab, theme] of Object.entries(workspace.paneThemes ?? {}))
207
+ if (ids[tab])
208
+ paneThemes[ids[tab]] = theme;
209
+ return { layout, paneThemes, ids };
210
+ }
211
+ /** Parses what native code returned; anything malformed is dropped, never thrown. */
212
+ export function normalizeWorkspaces(value) {
213
+ if (!isObject(value) || !Array.isArray(value.items))
214
+ return { ...EMPTY_WORKSPACES, items: [] };
215
+ const items = [];
216
+ for (const item of value.items) {
217
+ if (!isObject(item) || typeof item.id !== 'string' || !WORKSPACE_ID.test(item.id) || items.some(other => other.id === item.id))
218
+ continue;
219
+ const name = cleanName(item.name);
220
+ if (!name || !isObject(item.layout) || !isObject(item.layout.grid) || !isObject(item.layout.panels))
221
+ continue;
222
+ const paneThemes = isObject(item.paneThemes) ? Object.fromEntries(Object.entries(item.paneThemes).filter(([, theme]) => typeof theme === 'string' && THEME_ID.test(theme))) : {};
223
+ items.push({ id: item.id, name, savedAt: typeof item.savedAt === 'string' ? item.savedAt : '', layout: item.layout, paneThemes, ...(Array.isArray(item.decks) ? { decks: item.decks } : {}) });
224
+ if (items.length >= WORKSPACE_LIMITS.count)
225
+ break;
226
+ }
227
+ const fallback = typeof value.default === 'string' && items.some(item => item.id === value.default) ? value.default : null;
228
+ return { version: 1, default: fallback, items };
229
+ }
230
+ /** Adds or replaces (same id) a workspace; the list stays bounded. */
231
+ export function upsertWorkspace(store, workspace) {
232
+ const exists = store.items.some(item => item.id === workspace.id);
233
+ if (!exists && store.items.length >= WORKSPACE_LIMITS.count)
234
+ throw new Error(t('wb.ws.err.tooMany', { count: WORKSPACE_LIMITS.count }));
235
+ const items = exists ? store.items.map(item => (item.id === workspace.id ? workspace : item)) : [...store.items, workspace];
236
+ return { ...store, items };
237
+ }
238
+ export function removeWorkspace(store, id) {
239
+ return { version: 1, default: store.default === id ? null : store.default, items: store.items.filter(item => item.id !== id) };
240
+ }
241
+ export function renameWorkspace(store, id, name) {
242
+ const clean = cleanName(name);
243
+ if (!clean)
244
+ throw new Error('A workspace needs a name.');
245
+ return { ...store, items: store.items.map(item => (item.id === id ? { ...item, name: clean } : item)) };
246
+ }
247
+ export function setDefaultWorkspace(store, id) {
248
+ return { ...store, default: id && store.items.some(item => item.id === id) ? id : null };
249
+ }
250
+ //# sourceMappingURL=workspaceModel.js.map