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,165 @@
1
+ // Which language the app speaks. The owner picks "Follow the site" (default: the language the site
2
+ // itself is set to, as its tabs report their `<html lang>`), "Follow system" (the OS preference,
3
+ // read natively) or a language. The shell resolves that to a catalog, switches every window live,
4
+ // and hands native code (dialogs, notifications) and site tabs (the page runtime, plugins) exactly
5
+ // the strings they need through the shell-only `i18n_set`. Other local windows (a popover) follow
6
+ // through localStorage (same origin as the shell).
7
+ //
8
+ // export const language = createLanguage({ i18n, nativePrefixes: ['x.', 'kit.', 'plugin.', 'native.'], native: { invoke, listen } });
9
+ // await language.initShell(isNative());
10
+ //
11
+ // The panel's language picker takes the same object (`PanelSite.languages`).
12
+ import { direction, matchLocale, normalizeLocale } from "../../runtime/i18n.js";
13
+ /** Where the shell keeps its choice for the app's other local windows (localStorage). */
14
+ export const DEFAULT_STORAGE_KEY = `wb.language`;
15
+ /**
16
+ * The catalog to use for a preference, the site's reported language and the OS preferences.
17
+ * Automatic choices ("site", "system") only resolve to `supported` languages (default: all of
18
+ * `available`), through the normal fallback chain (pt-BR -> pt, zh-TW -> zh-Hant); a language
19
+ * picked explicitly applies whatever its tier.
20
+ */
21
+ export function resolveLocale(preference, siteLang, system, available, supported = available) {
22
+ if (preference === 'site') {
23
+ if (!siteLang)
24
+ return matchLocale(system, supported, 'en');
25
+ const site = matchLocale([siteLang], supported, '');
26
+ if (site)
27
+ return site;
28
+ // The site's language is a community translation: English (it is offered as a switch), not the system language.
29
+ return matchLocale([siteLang], available, '') ? 'en' : matchLocale(system, supported);
30
+ }
31
+ if (preference === 'system')
32
+ return matchLocale(system, supported);
33
+ return matchLocale([preference], available, matchLocale(system, supported));
34
+ }
35
+ /**
36
+ * The community language an automatic choice would have used had it been supported (the site's or
37
+ * the system's), or null: the panel offers it as a one-click switch.
38
+ */
39
+ export function communitySuggestion(preference, siteLang, system, available, supported = available) {
40
+ if (preference !== 'site' && preference !== 'system')
41
+ return null;
42
+ const wanted = resolveLocale(preference, siteLang, system, available, available);
43
+ return supported.includes(wanted) ? null : wanted;
44
+ }
45
+ export function createLanguage(options) {
46
+ const { i18n, nativePrefixes, native } = options;
47
+ const storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;
48
+ const available = i18n.available;
49
+ const supported = options.supported ? ['en', ...options.supported.filter(code => available.includes(code))] : available;
50
+ const current = {
51
+ preference: 'site',
52
+ siteLang: null,
53
+ system: [],
54
+ native: false,
55
+ };
56
+ const listeners = new Set();
57
+ function readStored() {
58
+ try {
59
+ const value = JSON.parse(localStorage.getItem(storageKey) ?? 'null');
60
+ return value && typeof value.locale === 'string' ? value : null;
61
+ }
62
+ catch {
63
+ return null;
64
+ }
65
+ }
66
+ function writeStored(value) {
67
+ try {
68
+ localStorage.setItem(storageKey, JSON.stringify(value));
69
+ }
70
+ catch { /* the choice still applies this session */ }
71
+ }
72
+ function browserLanguages() {
73
+ const list = typeof navigator === 'undefined' ? [] : [...(navigator.languages ?? []), navigator.language];
74
+ return list.filter((tag) => typeof tag === 'string' && !!normalizeLocale(tag));
75
+ }
76
+ function paint(locale) {
77
+ const root = document.documentElement;
78
+ root.lang = locale;
79
+ root.dir = direction(locale);
80
+ }
81
+ let syncing = Promise.resolve();
82
+ async function apply() {
83
+ const locale = resolveLocale(current.preference, current.siteLang, current.system, available, supported);
84
+ await i18n.setLocale(locale);
85
+ paint(i18n.locale);
86
+ writeStored({ preference: current.preference, locale: i18n.locale, siteLang: current.siteLang });
87
+ if (current.native) {
88
+ // Serialized: a quick switch must not let an older set of strings land last.
89
+ const strings = { locale: i18n.locale, preference: current.preference, messages: i18n.resolved(nativePrefixes) };
90
+ syncing = syncing.then(() => native.invoke('i18n_set', { strings })).catch(error => console.error('[i18n] native strings were not updated', error));
91
+ }
92
+ for (const listener of [...listeners])
93
+ listener();
94
+ }
95
+ /**
96
+ * Shell start: the saved preference (native), the OS languages, the last language the site
97
+ * reported, then the catalog; resolves once the first paint can be in the right language.
98
+ */
99
+ async function initShell(isNative) {
100
+ current.native = isNative;
101
+ const stored = readStored();
102
+ current.siteLang = stored?.siteLang ?? null;
103
+ let fromNative = null;
104
+ if (isNative) {
105
+ try {
106
+ fromNative = await native.invoke('i18n_get');
107
+ }
108
+ catch (error) {
109
+ console.error('[i18n] i18n_get failed', error);
110
+ }
111
+ }
112
+ current.preference = fromNative?.preference || stored?.preference || 'site';
113
+ current.system = [...(fromNative?.system ?? []), ...browserLanguages()];
114
+ if (isNative) {
115
+ // Site tabs say which language the site is in; "Follow the site" switches with it.
116
+ void native.listen('tab-state', ({ payload }) => {
117
+ const lang = normalizeLocale(payload.lang);
118
+ if (!lang || lang === current.siteLang)
119
+ return;
120
+ current.siteLang = lang;
121
+ if (current.preference === 'site')
122
+ void apply();
123
+ else
124
+ writeStored({ preference: current.preference, locale: i18n.locale, siteLang: lang });
125
+ });
126
+ }
127
+ await apply();
128
+ }
129
+ /** Another local window (a popover) and previews: the shell's last choice, kept current through storage events. */
130
+ async function initFollower(forced) {
131
+ const pick = async () => {
132
+ const locale = forced ? matchLocale([forced], available) : readStored()?.locale ?? matchLocale(browserLanguages(), supported);
133
+ await i18n.setLocale(locale);
134
+ paint(i18n.locale);
135
+ };
136
+ if (!forced) {
137
+ window.addEventListener('storage', event => { if (event.key === storageKey)
138
+ void pick(); });
139
+ }
140
+ await pick();
141
+ }
142
+ function state() {
143
+ return {
144
+ preference: current.preference, siteLang: current.siteLang, system: current.system, locale: i18n.locale,
145
+ community: communitySuggestion(current.preference, current.siteLang, current.system, available, supported),
146
+ };
147
+ }
148
+ async function set(preference) {
149
+ if (preference !== 'site' && preference !== 'system' && !available.includes(preference))
150
+ return;
151
+ current.preference = preference;
152
+ await apply();
153
+ }
154
+ function subscribe(listener) {
155
+ listeners.add(listener);
156
+ return () => { listeners.delete(listener); };
157
+ }
158
+ /** Development previews (`?lang=tr`): a fixed language without native code. */
159
+ async function forcePreview(tag) {
160
+ current.preference = matchLocale([tag], available);
161
+ await apply();
162
+ }
163
+ return { initShell, initFollower, state, set, subscribe, forcePreview, storageKey };
164
+ }
165
+ //# sourceMappingURL=language.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/language.ts"],"names":[],"mappings":"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","sourcesContent":["// Which language the app speaks. The owner picks \"Follow the site\" (default: the language the site\n// itself is set to, as its tabs report their `<html lang>`), \"Follow system\" (the OS preference,\n// read natively) or a language. The shell resolves that to a catalog, switches every window live,\n// and hands native code (dialogs, notifications) and site tabs (the page runtime, plugins) exactly\n// the strings they need through the shell-only `i18n_set`. Other local windows (a popover) follow\n// through localStorage (same origin as the shell).\n//\n// export const language = createLanguage({ i18n, nativePrefixes: ['x.', 'kit.', 'plugin.', 'native.'], native: { invoke, listen } });\n// await language.initShell(isNative());\n//\n// The panel's language picker takes the same object (`PanelSite.languages`).\n\nimport { direction, matchLocale, normalizeLocale } from '../../../runtime/src/i18n.ts';\nimport type { Invoke, Listen } from './bridge.ts';\n\n/** `site`: follow the site's own language. `system`: follow the OS. Otherwise a catalog tag. */\nexport type LanguagePreference = 'site' | 'system' | string;\n\n/** The part of a waybetter/i18n instance the language state drives. */\nexport type LanguageI18n = {\n readonly locale: string;\n readonly available: readonly string[];\n setLocale(locale: string): Promise<string>;\n resolved(prefixes?: readonly string[]): Record<string, string>;\n};\n\nexport type LanguageOptions = {\n i18n: LanguageI18n;\n /** Key prefixes native code and site tabs need; the shell hands exactly these over (`i18n_set`). */\n nativePrefixes: readonly string[];\n /** The app's Tauri `invoke` and `listen` (the language is set up before the shell frame is). */\n native: { invoke: Invoke; listen: Listen };\n /** Where the choice is kept for the app's other local windows (default `wb.language`). */\n storageKey?: string;\n /**\n * The supported tier: automatic choices (\"Follow the site\", \"Follow system\") resolve only to\n * these (English is always one). Any other catalog is a community language: it applies only\n * when picked explicitly. Default: every catalog is supported.\n */\n supported?: readonly string[];\n};\n\ntype NativeLanguage = { preference?: string; locale?: string; system?: string[] };\ntype Stored = { preference: LanguagePreference; locale: string; siteLang?: string | null };\n\n/** Where the shell keeps its choice for the app's other local windows (localStorage). */\nexport const DEFAULT_STORAGE_KEY = `wb.language`;\n\n/**\n * The catalog to use for a preference, the site's reported language and the OS preferences.\n * Automatic choices (\"site\", \"system\") only resolve to `supported` languages (default: all of\n * `available`), through the normal fallback chain (pt-BR -> pt, zh-TW -> zh-Hant); a language\n * picked explicitly applies whatever its tier.\n */\nexport function resolveLocale(preference: LanguagePreference, siteLang: string | null, system: readonly string[], available: readonly string[], supported: readonly string[] = available): string {\n if (preference === 'site') {\n if (!siteLang) return matchLocale(system, supported, 'en');\n const site = matchLocale([siteLang], supported, '');\n if (site) return site;\n // The site's language is a community translation: English (it is offered as a switch), not the system language.\n return matchLocale([siteLang], available, '') ? 'en' : matchLocale(system, supported);\n }\n if (preference === 'system') return matchLocale(system, supported);\n return matchLocale([preference], available, matchLocale(system, supported));\n}\n\n/**\n * The community language an automatic choice would have used had it been supported (the site's or\n * the system's), or null: the panel offers it as a one-click switch.\n */\nexport function communitySuggestion(preference: LanguagePreference, siteLang: string | null, system: readonly string[], available: readonly string[], supported: readonly string[] = available): string | null {\n if (preference !== 'site' && preference !== 'system') return null;\n const wanted = resolveLocale(preference, siteLang, system, available, available);\n return supported.includes(wanted) ? null : wanted;\n}\n\nexport type Language = ReturnType<typeof createLanguage>;\n\nexport function createLanguage(options: LanguageOptions) {\n const { i18n, nativePrefixes, native } = options;\n const storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n const available = i18n.available;\n const supported = options.supported ? ['en', ...options.supported.filter(code => available.includes(code))] : available;\n const current = {\n preference: 'site' as LanguagePreference,\n siteLang: null as string | null,\n system: [] as string[],\n native: false,\n };\n const listeners = new Set<() => void>();\n\n function readStored(): Stored | null {\n try {\n const value = JSON.parse(localStorage.getItem(storageKey) ?? 'null') as Stored | null;\n return value && typeof value.locale === 'string' ? value : null;\n } catch {\n return null;\n }\n }\n\n function writeStored(value: Stored) {\n try { localStorage.setItem(storageKey, JSON.stringify(value)); } catch { /* the choice still applies this session */ }\n }\n\n function browserLanguages(): string[] {\n const list = typeof navigator === 'undefined' ? [] : [...(navigator.languages ?? []), navigator.language];\n return list.filter((tag): tag is string => typeof tag === 'string' && !!normalizeLocale(tag));\n }\n\n function paint(locale: string) {\n const root = document.documentElement;\n root.lang = locale;\n root.dir = direction(locale);\n }\n\n let syncing: Promise<unknown> = Promise.resolve();\n\n async function apply() {\n const locale = resolveLocale(current.preference, current.siteLang, current.system, available, supported);\n await i18n.setLocale(locale);\n paint(i18n.locale);\n writeStored({ preference: current.preference, locale: i18n.locale, siteLang: current.siteLang });\n if (current.native) {\n // Serialized: a quick switch must not let an older set of strings land last.\n const strings = { locale: i18n.locale, preference: current.preference, messages: i18n.resolved(nativePrefixes) };\n syncing = syncing.then(() => native.invoke('i18n_set', { strings })).catch(error => console.error('[i18n] native strings were not updated', error));\n }\n for (const listener of [...listeners]) listener();\n }\n\n /**\n * Shell start: the saved preference (native), the OS languages, the last language the site\n * reported, then the catalog; resolves once the first paint can be in the right language.\n */\n async function initShell(isNative: boolean): Promise<void> {\n current.native = isNative;\n const stored = readStored();\n current.siteLang = stored?.siteLang ?? null;\n let fromNative: NativeLanguage | null = null;\n if (isNative) {\n try { fromNative = await native.invoke<NativeLanguage>('i18n_get'); } catch (error) { console.error('[i18n] i18n_get failed', error); }\n }\n current.preference = fromNative?.preference || stored?.preference || 'site';\n current.system = [...(fromNative?.system ?? []), ...browserLanguages()];\n if (isNative) {\n // Site tabs say which language the site is in; \"Follow the site\" switches with it.\n void native.listen<{ lang?: string }>('tab-state', ({ payload }) => {\n const lang = normalizeLocale(payload.lang);\n if (!lang || lang === current.siteLang) return;\n current.siteLang = lang;\n if (current.preference === 'site') void apply();\n else writeStored({ preference: current.preference, locale: i18n.locale, siteLang: lang });\n });\n }\n await apply();\n }\n\n /** Another local window (a popover) and previews: the shell's last choice, kept current through storage events. */\n async function initFollower(forced?: string | null): Promise<void> {\n const pick = async () => {\n const locale = forced ? matchLocale([forced], available) : readStored()?.locale ?? matchLocale(browserLanguages(), supported);\n await i18n.setLocale(locale);\n paint(i18n.locale);\n };\n if (!forced) {\n window.addEventListener('storage', event => { if (event.key === storageKey) void pick(); });\n }\n await pick();\n }\n\n function state() {\n return {\n preference: current.preference, siteLang: current.siteLang, system: current.system, locale: i18n.locale,\n community: communitySuggestion(current.preference, current.siteLang, current.system, available, supported),\n };\n }\n\n async function set(preference: LanguagePreference): Promise<void> {\n if (preference !== 'site' && preference !== 'system' && !available.includes(preference)) return;\n current.preference = preference;\n await apply();\n }\n\n function subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => { listeners.delete(listener); };\n }\n\n /** Development previews (`?lang=tr`): a fixed language without native code. */\n async function forcePreview(tag: string): Promise<void> {\n current.preference = matchLocale([tag], available);\n await apply();\n }\n\n return { initShell, initFollower, state, set, subscribe, forcePreview, storageKey };\n}\n"]}
@@ -0,0 +1,34 @@
1
+ export type GalleryImage = {
2
+ path: string;
3
+ name: string;
4
+ folder: string;
5
+ modifiedMs: number;
6
+ size: number;
7
+ };
8
+ export type ClipItem = {
9
+ id: string;
10
+ kind: 'text' | 'image';
11
+ text?: string;
12
+ file?: string;
13
+ hash: string;
14
+ at: number;
15
+ };
16
+ export type MediaSettings = {
17
+ folders: string[];
18
+ clipboardEnabled: boolean;
19
+ clipboardMax: number;
20
+ };
21
+ export type TabInfo = {
22
+ id: string;
23
+ url: string;
24
+ };
25
+ export declare const CLIP_MAX_LIMIT = 100;
26
+ /** The tab an attachment goes to: the active tab if it can take one, else the most recent one that can. */
27
+ export declare function attachTarget(tabs: TabInfo[], activeId: string | undefined, canAttach: (url: string) => boolean, recent?: string[]): TabInfo | null;
28
+ /** Gallery folders shown as their last path segment (Windows or POSIX separators). */
29
+ export declare function folderLabel(folder: string): string;
30
+ export declare function clampClipMax(value: number): number;
31
+ /** Removing a folder is the only folder change the shell can make; adding goes through the native dialog. */
32
+ export declare function withoutFolder(settings: MediaSettings, folder: string): MediaSettings;
33
+ export declare function clipPreview(item: ClipItem, max?: number): string;
34
+ export declare function relativeTime(ms: number, now?: number): string;
@@ -0,0 +1,53 @@
1
+ // Pure model for the Media side panel (gallery folders + clipboard history). No Tauri/DOM
2
+ // imports, so it is unit-tested under node. The panel never posts: it only asks native code to
3
+ // attach an image to, or insert text into, one site tab's composer (`site.media.canAttach` says
4
+ // which pages have one).
5
+ import { formatNumber, t } from "./i18n.js";
6
+ export const CLIP_MAX_LIMIT = 100;
7
+ /** The tab an attachment goes to: the active tab if it can take one, else the most recent one that can. */
8
+ export function attachTarget(tabs, activeId, canAttach, recent = []) {
9
+ const active = tabs.find(tab => tab.id === activeId);
10
+ if (active && canAttach(active.url))
11
+ return active;
12
+ for (const id of recent) {
13
+ const tab = tabs.find(candidate => candidate.id === id);
14
+ if (tab && canAttach(tab.url))
15
+ return tab;
16
+ }
17
+ return tabs.find(tab => canAttach(tab.url)) ?? null;
18
+ }
19
+ /** Gallery folders shown as their last path segment (Windows or POSIX separators). */
20
+ export function folderLabel(folder) {
21
+ const parts = folder.split(/[\\/]+/).filter(Boolean);
22
+ return parts[parts.length - 1] ?? folder;
23
+ }
24
+ export function clampClipMax(value) {
25
+ if (!Number.isFinite(value))
26
+ return 30;
27
+ return Math.min(CLIP_MAX_LIMIT, Math.max(1, Math.round(value)));
28
+ }
29
+ /** Removing a folder is the only folder change the shell can make; adding goes through the native dialog. */
30
+ export function withoutFolder(settings, folder) {
31
+ return { ...settings, folders: settings.folders.filter(f => f !== folder) };
32
+ }
33
+ export function clipPreview(item, max = 80) {
34
+ if (item.kind === 'image')
35
+ return t('wb.media.image');
36
+ const flat = (item.text ?? '').replace(/\s+/g, ' ').trim();
37
+ return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
38
+ }
39
+ export function relativeTime(ms, now = Date.now()) {
40
+ const seconds = Math.max(0, Math.round((now - ms) / 1000));
41
+ if (seconds < 60)
42
+ return t('wb.media.now');
43
+ // Compact units in the active language ("5m", "5 dk", "5分").
44
+ const unit = (value, name) => formatNumber(value, { style: 'unit', unit: name, unitDisplay: 'narrow' });
45
+ const minutes = Math.round(seconds / 60);
46
+ if (minutes < 60)
47
+ return unit(minutes, 'minute');
48
+ const hours = Math.round(minutes / 60);
49
+ if (hours < 24)
50
+ return unit(hours, 'hour');
51
+ return unit(Math.round(hours / 24), 'day');
52
+ }
53
+ //# sourceMappingURL=mediaModel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediaModel.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/mediaModel.ts"],"names":[],"mappings":"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","sourcesContent":["// Pure model for the Media side panel (gallery folders + clipboard history). No Tauri/DOM\n// imports, so it is unit-tested under node. The panel never posts: it only asks native code to\n// attach an image to, or insert text into, one site tab's composer (`site.media.canAttach` says\n// which pages have one).\n\nimport { formatNumber, t } from './i18n.ts';\n\nexport type GalleryImage = { path: string; name: string; folder: string; modifiedMs: number; size: number };\nexport type ClipItem = { id: string; kind: 'text' | 'image'; text?: string; file?: string; hash: string; at: number };\nexport type MediaSettings = { folders: string[]; clipboardEnabled: boolean; clipboardMax: number };\nexport type TabInfo = { id: string; url: string };\n\nexport const CLIP_MAX_LIMIT = 100;\n\n/** The tab an attachment goes to: the active tab if it can take one, else the most recent one that can. */\nexport function attachTarget(tabs: TabInfo[], activeId: string | undefined, canAttach: (url: string) => boolean, recent: string[] = []): TabInfo | null {\n const active = tabs.find(tab => tab.id === activeId);\n if (active && canAttach(active.url)) return active;\n for (const id of recent) {\n const tab = tabs.find(candidate => candidate.id === id);\n if (tab && canAttach(tab.url)) return tab;\n }\n return tabs.find(tab => canAttach(tab.url)) ?? null;\n}\n\n/** Gallery folders shown as their last path segment (Windows or POSIX separators). */\nexport function folderLabel(folder: string): string {\n const parts = folder.split(/[\\\\/]+/).filter(Boolean);\n return parts[parts.length - 1] ?? folder;\n}\n\nexport function clampClipMax(value: number): number {\n if (!Number.isFinite(value)) return 30;\n return Math.min(CLIP_MAX_LIMIT, Math.max(1, Math.round(value)));\n}\n\n/** Removing a folder is the only folder change the shell can make; adding goes through the native dialog. */\nexport function withoutFolder(settings: MediaSettings, folder: string): MediaSettings {\n return { ...settings, folders: settings.folders.filter(f => f !== folder) };\n}\n\nexport function clipPreview(item: ClipItem, max = 80): string {\n if (item.kind === 'image') return t('wb.media.image');\n const flat = (item.text ?? '').replace(/\\s+/g, ' ').trim();\n return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;\n}\n\nexport function relativeTime(ms: number, now = Date.now()): string {\n const seconds = Math.max(0, Math.round((now - ms) / 1000));\n if (seconds < 60) return t('wb.media.now');\n // Compact units in the active language (\"5m\", \"5 dk\", \"5分\").\n const unit = (value: number, name: 'minute' | 'hour' | 'day') => formatNumber(value, { style: 'unit', unit: name, unitDisplay: 'narrow' });\n const minutes = Math.round(seconds / 60);\n if (minutes < 60) return unit(minutes, 'minute');\n const hours = Math.round(minutes / 60);\n if (hours < 24) return unit(hours, 'hour');\n return unit(Math.round(hours / 24), 'day');\n}\n"]}
@@ -0,0 +1,54 @@
1
+ {
2
+ "wb.menu.label": "Settings and more",
3
+ "wb.menu.accountsRow": "Settings and more…",
4
+ "wb.menu.newColumn": "New deck column",
5
+ "wb.menu.theme": "Theme",
6
+ "wb.menu.moreAppearance": "More in Appearance…",
7
+ "wb.menu.moreLanguages": "More languages…",
8
+ "wb.menu.zoom": "Zoom",
9
+ "wb.menu.zoomIn": "Zoom in",
10
+ "wb.menu.zoomOut": "Zoom out",
11
+ "wb.menu.zoomReset": "Reset zoom",
12
+ "wb.menu.zoomNone": "This tab has no page to zoom",
13
+ "wb.menu.zoomChip": "Zoom {percent}. Click to reset.",
14
+ "wb.menu.saveLayout": "Save layout…",
15
+ "wb.menu.noWorkspaces": "No saved workspaces yet",
16
+ "wb.menu.shortcuts": "Keyboard shortcuts…",
17
+ "wb.menu.palette": "Command palette",
18
+ "wb.menu.developer": "Developer",
19
+ "wb.menu.pluginsFolder": "Open plugins folder",
20
+ "wb.menu.about": "About {product}",
21
+ "wb.menu.section": "{section}…",
22
+ "wb.menu.find": "Find in page…",
23
+ "wb.menu.findField": "Find in page",
24
+ "wb.menu.findHint": "Finds what this page has loaded so far",
25
+ "wb.menu.findCount": "{index}/{count}",
26
+ "wb.menu.findTotal": "{count, plural, one {# match} other {# matches}}",
27
+ "wb.menu.findNone": "No matches",
28
+ "wb.menu.findNext": "Next match",
29
+ "wb.menu.findPrevious": "Previous match",
30
+ "wb.menu.findClose": "Close find bar",
31
+ "wb.menu.updateCheck": "Check for updates",
32
+ "wb.menu.updateChecking": "Checking…",
33
+ "wb.menu.updateUpToDate": "Up to date",
34
+ "wb.menu.updateUpToDateVersion": "Up to date · {version}",
35
+ "wb.menu.updateDownloading": "Downloading {version}…",
36
+ "wb.menu.updateInstalling": "Installing {version}…",
37
+ "wb.menu.updateRestart": "Restart to update",
38
+ "wb.menu.updateFailed": "Could not check",
39
+ "wb.menu.updateFailedHint": "The update server did not answer. Nothing is wrong with the app; it checks again later on its own.",
40
+ "wb.menu.safe": "Safe mode",
41
+ "wb.menu.safeRestart": "Restart in safe mode…",
42
+ "wb.menu.safeQuestion": "Restart the tabs in safe mode?",
43
+ "wb.menu.safeExplain": "Every tab loads again with plugins, themes, custom CSS and page features off, for this run only. Your setup is back the next time you start the app.",
44
+ "wb.menu.safeConfirm": "Restart tabs in safe mode",
45
+ "wb.menu.safeLeave": "Leave safe mode",
46
+ "wb.menu.safeLeaveShort": "Leave",
47
+ "wb.menu.safeChip": "Safe mode is on: plugins, themes, custom CSS and page features are off for this run. Click to leave; the tabs load again with your setup.",
48
+ "wb.menu.report": "Report a problem…",
49
+ "wb.menu.reportTitle": "Report a problem",
50
+ "wb.menu.reportLede": "This is everything the report contains: versions and what is switched on. No account, no address, nothing from the pages you have open. Copy it, then paste it into your report.",
51
+ "wb.menu.reportOpen": "Open the issue page",
52
+ "wb.menu.reportNoPage": "This app has no public issue page yet. Copy the text and send it to the developer.",
53
+ "wb.menu.strings": "Languages"
54
+ }
@@ -0,0 +1,277 @@
1
+ import type { UpdateStatus } from '../updateModel.ts';
2
+ import EN from './menuMessages.en.json';
3
+ import { type Params } from './i18n.ts';
4
+ import type { IconName } from './icons.tsx';
5
+ /** The menu's English (`wb.menu.*`), for the catalogs. */
6
+ export declare const MENU_MESSAGES: Readonly<Record<string, string>>;
7
+ type MenuKey = keyof typeof EN;
8
+ /** A menu message's name: its key without the `wb.menu.` prefix. */
9
+ export type MenuWord = MenuKey extends `wb.menu.${infer Name}` ? Name : never;
10
+ /** A menu message in the active language; English from menuMessages.en.json until a catalog has it. */
11
+ export declare function menuText(name: MenuWord, params?: Params): string;
12
+ /** The rows the frame brings. Each shows only when the app serves what it needs (`builtinAvailable`). */
13
+ export declare const MENU_BUILTINS: readonly ["new-tab", "split-right", "split-down", "new-column", "language", "theme", "mode", "zoom", "plugins", "store", "strings", "workspaces", "find", "shortcuts", "palette", "developer", "updates", "safe-mode", "report", "about", "settings"];
14
+ export type BuiltinMenuItem = typeof MENU_BUILTINS[number];
15
+ /** A row of the app's own. */
16
+ export type MenuItemSpec = {
17
+ /** Unique in the menu (never a built-in's name). */
18
+ id: string;
19
+ label(): string;
20
+ icon?: IconName;
21
+ /** Its keys, written like `Ctrl+Shift+D` (shown as the platform writes them; the app handles the keys). */
22
+ shortcut?: string;
23
+ /** Quiet text at the end of the row instead of a shortcut (a count, a version). */
24
+ hint?(): string;
25
+ /** Leave the row out while this is false. */
26
+ when?(): boolean;
27
+ /** A toggle: the row is a checkbox showing this state; `run` flips it. */
28
+ checked?(): boolean;
29
+ run?(): void | Promise<void>;
30
+ /** A submenu instead of an action (its rows may have submenus of their own). */
31
+ submenu?(): MenuItemSpec[];
32
+ /** Starts a new group (a rule above this row) inside a submenu. */
33
+ separated?: boolean;
34
+ /** The menu stays open after `run` (a toggle someone may flip back). */
35
+ keepOpen?: boolean;
36
+ };
37
+ export type MenuEntry = BuiltinMenuItem | MenuItemSpec;
38
+ /** Ordered groups; a rule is drawn between two groups. */
39
+ export type MenuGroups = ReadonlyArray<ReadonlyArray<MenuEntry>>;
40
+ /** One language of the app (a row of its `languages.json`). */
41
+ export type MenuLanguage = {
42
+ code: string;
43
+ name: string;
44
+ englishName: string;
45
+ dir: 'ltr' | 'rtl';
46
+ tier: 'supported' | 'community';
47
+ };
48
+ /** The app's language state (frame/language.ts `createLanguage`), as the panel's picker takes it. */
49
+ export type MenuLanguages = {
50
+ list: readonly MenuLanguage[];
51
+ state(): {
52
+ preference: string;
53
+ siteLang: string | null;
54
+ locale: string;
55
+ };
56
+ subscribe(listener: () => void): () => void;
57
+ set(preference: string): Promise<void>;
58
+ };
59
+ /** The app's modes (Basic / Advanced / Power User): the panel's `menuModes()` gives this. */
60
+ export type MenuModes = {
61
+ list(): ReadonlyArray<{
62
+ id: string;
63
+ label: string;
64
+ }>;
65
+ /** The mode in use (null: none chosen yet). */
66
+ current(): Promise<string | null>;
67
+ /** How many of the owner's own changes choosing `to` would replace (0: nothing to ask). */
68
+ changes(to: string): Promise<number>;
69
+ /** Applies `to`, keeping the owner's own changes or not. */
70
+ apply(to: string, keep: boolean): Promise<void>;
71
+ /** How the features relate to the mode in use (omit: the menu never says "custom"). */
72
+ status?(): Promise<MenuModeStatus>;
73
+ /** Applies the mode in use again as it is now: exactly what `status()` listed. */
74
+ reapply?(): Promise<void>;
75
+ /** The "new features" note was looked at; it is not shown again. */
76
+ seen?(): Promise<void>;
77
+ };
78
+ /**
79
+ * A mode is a starting point. `custom`: the features are no longer what the mode starts from;
80
+ * `on` / `off`: the names of what applying it again would turn on and off; `added`: how many of
81
+ * those the mode gained in an update since it was applied.
82
+ */
83
+ export type MenuModeStatus = {
84
+ custom: boolean;
85
+ on: string[];
86
+ off: string[];
87
+ added: number;
88
+ };
89
+ /** Lines an app adds to the "Report a problem" summary (reportModel.ts): ids only, never anything about the person. */
90
+ export type ReportDetails = ReadonlyArray<{
91
+ label: string;
92
+ values: readonly string[];
93
+ }>;
94
+ /** `ShellSite.menu`: the app menu's rows and what the built-in ones need from the app. */
95
+ export type ShellMenu = {
96
+ /** The rows, in order. A string is a built-in row, an object one of the app's. Default: `DEFAULT_MENU`. */
97
+ groups?: MenuGroups;
98
+ /** The Language submenu; omit for an app in one language. */
99
+ languages?: MenuLanguages;
100
+ /** The Mode submenu; omit for an app without modes. */
101
+ modes?: MenuModes;
102
+ /** The app's version, shown on the Updates row. */
103
+ version?(): Promise<string>;
104
+ /**
105
+ * "Report a problem": the project's new-issue page (https; opened bare in the system browser, the
106
+ * summary is never put in the URL) and lines the app adds to the summary (a fixed English label
107
+ * and ids: what paused itself, which areas are on). Without `issueUrl` the dialog still shows and
108
+ * copies the summary; its button is off and says there is no public page yet.
109
+ */
110
+ report?: {
111
+ issueUrl?: string;
112
+ details?(): ReportDetails | Promise<ReportDetails>;
113
+ };
114
+ /** Opens the app's shortcuts sheet ("Keyboard shortcuts…"); without one the row opens the command palette. */
115
+ shortcuts?(): void;
116
+ };
117
+ /** The menu an app gets without saying anything: every built-in row it can serve. */
118
+ export declare const DEFAULT_MENU: MenuGroups;
119
+ /** `groups` with the app's `items` put next to the row `anchor` (after it, or before). Without that row they form a last group. */
120
+ export declare function menuWith(groups: MenuGroups, anchor: string, items: readonly MenuEntry[], where?: 'after' | 'before'): MenuGroups;
121
+ /** `groups` without the rows named. */
122
+ export declare function menuWithout(groups: MenuGroups, ...ids: string[]): MenuGroups;
123
+ /** What the app serves, as far as the built-in rows care. */
124
+ export type MenuEnv = {
125
+ /** Decks of site columns (`site.deck`). */
126
+ decks: boolean;
127
+ /** `menu.languages`. */
128
+ languages: boolean;
129
+ /** `site.themes`. */
130
+ themes: boolean;
131
+ /** `menu.modes` with at least one mode. */
132
+ modes: boolean;
133
+ /** `features`: native page zoom (`tab_zoom`), find in page (`tab_find`), the Store, workspaces, developer mode, the updater. */
134
+ zoom: boolean;
135
+ find: boolean;
136
+ /** `features.safeMode`: safe mode for one run (`safe_mode_get/set`, the host's own). */
137
+ safeMode: boolean;
138
+ store: boolean;
139
+ /** `features.strings`: the panel has the Languages section (string packs). */
140
+ strings: boolean;
141
+ workspaces: boolean;
142
+ developer: boolean;
143
+ updates: boolean;
144
+ };
145
+ /** Whether the app can serve a built-in row: a row that would do nothing is never shown. */
146
+ export declare function builtinAvailable(id: BuiltinMenuItem, env: MenuEnv): boolean;
147
+ /**
148
+ * The entries the menu shows, group by group: built-in rows the app cannot serve and rows whose
149
+ * `when()` says no are left out, a row listed twice shows once, a group left empty goes (so no
150
+ * rule is ever doubled), and an unknown name is ignored.
151
+ */
152
+ export declare function planMenu(groups: MenuGroups, env: MenuEnv): MenuEntry[][];
153
+ export type MenuItemRow = {
154
+ kind: 'item';
155
+ id: string;
156
+ label: string;
157
+ icon?: IconName;
158
+ shortcut?: string;
159
+ hint?: string;
160
+ disabled?: boolean;
161
+ /** A choice among its neighbours (radio) or a toggle (checkbox), with `checked`. */
162
+ check?: 'radio' | 'checkbox';
163
+ checked?: boolean;
164
+ /** Opens a submenu (its rows come from the menu, by this row's id). */
165
+ submenu?: boolean;
166
+ keepOpen?: boolean;
167
+ /** The label's own language and direction (a language's native name). */
168
+ lang?: string;
169
+ dir?: 'ltr' | 'rtl';
170
+ /** The row's tooltip (a plain sentence that does not fit the row). */
171
+ title?: string;
172
+ /** A theme's colors, drawn as three dots (`ThemeAdapter.dots`). */
173
+ swatch?: {
174
+ page: string;
175
+ bg: string;
176
+ border: string;
177
+ text: string;
178
+ accent: string;
179
+ };
180
+ run?(): unknown;
181
+ };
182
+ export type MenuRow = MenuItemRow | {
183
+ kind: 'separator';
184
+ }
185
+ /** Words that are not a choice: a question above its answers, an empty list, an error. */
186
+ | {
187
+ kind: 'note';
188
+ id: string;
189
+ title: string;
190
+ text?: string;
191
+ tone?: 'error';
192
+ }
193
+ /** The zoom row: − 100% + and a reset, in one line. */
194
+ | {
195
+ kind: 'zoom';
196
+ id: 'zoom';
197
+ };
198
+ /** Groups of rows as one list with a rule between two groups. */
199
+ export declare function joinGroups(groups: ReadonlyArray<readonly MenuRow[]>): MenuRow[];
200
+ /** The app's own entries as rows (`submenu` rows are looked up again when they open). */
201
+ export declare function specRows(specs: readonly MenuItemSpec[]): MenuRow[];
202
+ /** The app's entry with this id, anywhere in its groups or their submenus. */
203
+ export declare function findSpec(groups: MenuGroups, id: string): MenuItemSpec | null;
204
+ /** Arrow keys, Home and End over `count` stops; wraps around. -1 (nothing focused) enters at an end. */
205
+ export declare function moveStop(index: number, key: string, count: number): number;
206
+ /**
207
+ * Type-ahead: the next stop after `from` whose label starts with what was typed (accents and case
208
+ * ignored). One letter typed again cycles through the labels that start with it. -1: none.
209
+ */
210
+ export declare function typeahead(labels: readonly string[], from: number, typed: string): number;
211
+ /** The keys that open and close a submenu: they follow the reading direction. */
212
+ export declare function submenuKeys(rtl: boolean): {
213
+ open: string;
214
+ close: string;
215
+ };
216
+ /**
217
+ * The left edge of a submenu `width` wide beside its menu (`parent`), in a window `viewport` wide.
218
+ * The menu hangs at one edge of the window (under its button at the end, under the logo at the
219
+ * start): the submenu opens toward the middle, else on the other side, else over the menu, and
220
+ * always stays `edge` pixels inside the window.
221
+ */
222
+ export declare function submenuLeft(parent: {
223
+ left: number;
224
+ right: number;
225
+ }, width: number, viewport: number, edge?: number): number;
226
+ /** A shortcut as the platform writes it: `Ctrl+Shift+T` on Windows and Linux, `⇧⌘T` on macOS. */
227
+ export declare function shortcutText(shortcut: string, mac: boolean): string;
228
+ /**
229
+ * The Language submenu: follow the site, follow the system, then the supported languages by their
230
+ * own names (the one chosen is checked; a community language in use is listed too, so the check is
231
+ * never missing), then the way to the full list in Settings.
232
+ */
233
+ export declare function languageRows(list: readonly MenuLanguage[], state: {
234
+ preference: string;
235
+ siteLang: string | null;
236
+ locale: string;
237
+ }, words: {
238
+ site: string;
239
+ system: string;
240
+ more: string;
241
+ }): MenuRow[];
242
+ /** The preference a Language row stands for (`lang:tr` → `tr`), or null for "More languages…". */
243
+ export declare function languageChoice(id: string): string | null;
244
+ /** Page zoom limits, as native code clamps them (waybetter-host `zoom.rs`). */
245
+ export declare const ZOOM_MIN = 0.25;
246
+ export declare const ZOOM_MAX = 5;
247
+ /** The steps − and + move through (a browser's). */
248
+ export declare const ZOOM_STEPS: readonly [0.25, 0.33, 0.5, 0.67, 0.75, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5];
249
+ /** The next step up (`1`) or down (`-1`) from `factor`, or 100% (`0`). Stays inside the limits. */
250
+ export declare function zoomStep(factor: number, direction: 1 | -1 | 0): number;
251
+ /** The Updates row: what it says and what choosing it does. */
252
+ export type UpdateRow = {
253
+ label: string;
254
+ /** Quiet text at the end of the row: the state, or the version while nothing is happening. */
255
+ hint?: string;
256
+ /** A plain sentence for the row's tooltip (why a check did not get through). */
257
+ title?: string;
258
+ /** `check`: ask the updater now. `restart`: install the downloaded update. `open`: the Updates section. `wait`: nothing, a step is running. */
259
+ action: 'check' | 'restart' | 'open' | 'wait';
260
+ };
261
+ /**
262
+ * The Updates row for the updater's status. `asked`: the owner asked for a check in this menu;
263
+ * only then does a check that did not get through say so (the timer's own failures stay quiet),
264
+ * and it says it calmly: a short state, never the error text.
265
+ */
266
+ export declare function updateRow(status: UpdateStatus, asked: boolean, version: string): UpdateRow;
267
+ /**
268
+ * What the find bar says about a search: "3/17" (the active match of the total), the total alone
269
+ * while no match is active, "No matches" for none. `number` writes a number in the active language.
270
+ */
271
+ export declare function findLabel(counts: {
272
+ count: number;
273
+ index: number;
274
+ }, number?: (value: number) => string): string;
275
+ /** Whole percent of a factor (1.1 → 110). */
276
+ export declare const zoomPercent: (factor: number) => number;
277
+ export {};