waybetter 0.1.1 → 0.7.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 (537) hide show
  1. package/README.md +139 -6
  2. package/bin/waybetter.mjs +43 -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/release.mjs +437 -0
  9. package/cli/releasecheck.mjs +15 -0
  10. package/cli/remote.mjs +260 -0
  11. package/cli/store.mjs +378 -0
  12. package/cli/strings.mjs +123 -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 +61 -0
  74. package/dist/runtime/stringPackTranslate.js +267 -0
  75. package/dist/runtime/stringPackTranslate.js.map +1 -0
  76. package/dist/runtime/stringPacks.d.ts +248 -0
  77. package/dist/runtime/stringPacks.js +610 -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/themeBar.d.ts +28 -0
  89. package/dist/runtime/themeBar.js +82 -0
  90. package/dist/runtime/themeBar.js.map +1 -0
  91. package/dist/runtime/themeChoice.d.ts +52 -0
  92. package/dist/runtime/themeChoice.js +69 -0
  93. package/dist/runtime/themeChoice.js.map +1 -0
  94. package/dist/runtime/themeComponents.d.ts +435 -0
  95. package/dist/runtime/themeComponents.js +476 -0
  96. package/dist/runtime/themeComponents.js.map +1 -0
  97. package/dist/runtime/themeDecor.d.ts +73 -0
  98. package/dist/runtime/themeDecor.js +133 -0
  99. package/dist/runtime/themeDecor.js.map +1 -0
  100. package/dist/runtime/themeDerive.d.ts +69 -0
  101. package/dist/runtime/themeDerive.js +117 -0
  102. package/dist/runtime/themeDerive.js.map +1 -0
  103. package/dist/runtime/themeDoctor.d.ts +52 -0
  104. package/dist/runtime/themeDoctor.js +112 -0
  105. package/dist/runtime/themeDoctor.js.map +1 -0
  106. package/dist/runtime/themeGuards.d.ts +60 -0
  107. package/dist/runtime/themeGuards.js +235 -0
  108. package/dist/runtime/themeGuards.js.map +1 -0
  109. package/dist/runtime/themeIcons.d.ts +130 -0
  110. package/dist/runtime/themeIcons.js +271 -0
  111. package/dist/runtime/themeIcons.js.map +1 -0
  112. package/dist/runtime/themeInk.d.ts +37 -0
  113. package/dist/runtime/themeInk.js +111 -0
  114. package/dist/runtime/themeInk.js.map +1 -0
  115. package/dist/runtime/themeInvariants.d.ts +39 -0
  116. package/dist/runtime/themeInvariants.js +273 -0
  117. package/dist/runtime/themeInvariants.js.map +1 -0
  118. package/dist/runtime/themeRuntime.d.ts +114 -0
  119. package/dist/runtime/themeRuntime.js +570 -0
  120. package/dist/runtime/themeRuntime.js.map +1 -0
  121. package/dist/runtime/themeSchema.d.ts +10 -0
  122. package/dist/runtime/themeSchema.js +150 -0
  123. package/dist/runtime/themeSchema.js.map +1 -0
  124. package/dist/runtime/themeSpec.d.ts +263 -0
  125. package/dist/runtime/themeSpec.js +435 -0
  126. package/dist/runtime/themeSpec.js.map +1 -0
  127. package/dist/runtime/themeTokens.d.ts +12 -0
  128. package/dist/runtime/themeTokens.js +14 -6
  129. package/dist/runtime/themeTokens.js.map +1 -1
  130. package/dist/runtime/themeVariants.d.ts +30 -0
  131. package/dist/runtime/themeVariants.js +53 -0
  132. package/dist/runtime/themeVariants.js.map +1 -0
  133. package/dist/runtime/ui.d.ts +192 -0
  134. package/dist/runtime/ui.js +926 -0
  135. package/dist/runtime/ui.js.map +1 -0
  136. package/dist/shell/InstallDialog.d.ts +40 -0
  137. package/dist/shell/InstallDialog.js +176 -0
  138. package/dist/shell/InstallDialog.js.map +1 -0
  139. package/dist/shell/StoreView.d.ts +78 -0
  140. package/dist/shell/StoreView.js +108 -0
  141. package/dist/shell/StoreView.js.map +1 -0
  142. package/dist/shell/addressModel.js.map +1 -1
  143. package/dist/shell/chrome.js.map +1 -1
  144. package/dist/shell/deckModel.d.ts +117 -0
  145. package/dist/shell/deckModel.js +267 -0
  146. package/dist/shell/deckModel.js.map +1 -0
  147. package/dist/shell/frame/AccountSwitcher.d.ts +42 -0
  148. package/dist/shell/frame/AccountSwitcher.js +243 -0
  149. package/dist/shell/frame/AccountSwitcher.js.map +1 -0
  150. package/dist/shell/frame/AddColumnDialog.d.ts +8 -0
  151. package/dist/shell/frame/AddColumnDialog.js +81 -0
  152. package/dist/shell/frame/AddColumnDialog.js.map +1 -0
  153. package/dist/shell/frame/AppMenu.d.ts +44 -0
  154. package/dist/shell/frame/AppMenu.js +721 -0
  155. package/dist/shell/frame/AppMenu.js.map +1 -0
  156. package/dist/shell/frame/CommandPalette.d.ts +7 -0
  157. package/dist/shell/frame/CommandPalette.js +118 -0
  158. package/dist/shell/frame/CommandPalette.js.map +1 -0
  159. package/dist/shell/frame/DeckView.d.ts +13 -0
  160. package/dist/shell/frame/DeckView.js +287 -0
  161. package/dist/shell/frame/DeckView.js.map +1 -0
  162. package/dist/shell/frame/FindBar.d.ts +10 -0
  163. package/dist/shell/frame/FindBar.js +108 -0
  164. package/dist/shell/frame/FindBar.js.map +1 -0
  165. package/dist/shell/frame/MediaPanel.d.ts +8 -0
  166. package/dist/shell/frame/MediaPanel.js +76 -0
  167. package/dist/shell/frame/MediaPanel.js.map +1 -0
  168. package/dist/shell/frame/NewTabPage.d.ts +9 -0
  169. package/dist/shell/frame/NewTabPage.js +71 -0
  170. package/dist/shell/frame/NewTabPage.js.map +1 -0
  171. package/dist/shell/frame/PaneTheme.d.ts +16 -0
  172. package/dist/shell/frame/PaneTheme.js +67 -0
  173. package/dist/shell/frame/PaneTheme.js.map +1 -0
  174. package/dist/shell/frame/ReportDialog.d.ts +3 -0
  175. package/dist/shell/frame/ReportDialog.js +95 -0
  176. package/dist/shell/frame/ReportDialog.js.map +1 -0
  177. package/dist/shell/frame/Shell.d.ts +9 -0
  178. package/dist/shell/frame/Shell.js +1139 -0
  179. package/dist/shell/frame/Shell.js.map +1 -0
  180. package/dist/shell/frame/Titlebar.d.ts +17 -0
  181. package/dist/shell/frame/Titlebar.js +79 -0
  182. package/dist/shell/frame/Titlebar.js.map +1 -0
  183. package/dist/shell/frame/TitlebarExtras.d.ts +4 -0
  184. package/dist/shell/frame/TitlebarExtras.js +202 -0
  185. package/dist/shell/frame/TitlebarExtras.js.map +1 -0
  186. package/dist/shell/frame/WebPanel.d.ts +4 -0
  187. package/dist/shell/frame/WebPanel.js +185 -0
  188. package/dist/shell/frame/WebPanel.js.map +1 -0
  189. package/dist/shell/frame/accountModel.d.ts +49 -0
  190. package/dist/shell/frame/accountModel.js +67 -0
  191. package/dist/shell/frame/accountModel.js.map +1 -0
  192. package/dist/shell/frame/accountSwitcher.css +91 -0
  193. package/dist/shell/frame/appI18n.d.ts +44 -0
  194. package/dist/shell/frame/appI18n.js +64 -0
  195. package/dist/shell/frame/appI18n.js.map +1 -0
  196. package/dist/shell/frame/appMenu.css +127 -0
  197. package/dist/shell/frame/backupModel.d.ts +38 -0
  198. package/dist/shell/frame/backupModel.js +192 -0
  199. package/dist/shell/frame/backupModel.js.map +1 -0
  200. package/dist/shell/frame/boot.d.ts +8 -0
  201. package/dist/shell/frame/boot.js +37 -0
  202. package/dist/shell/frame/boot.js.map +1 -0
  203. package/dist/shell/frame/brand.d.ts +1 -0
  204. package/dist/shell/frame/brand.js +4 -0
  205. package/dist/shell/frame/brand.js.map +1 -0
  206. package/dist/shell/frame/bridge.d.ts +35 -0
  207. package/dist/shell/frame/bridge.js +70 -0
  208. package/dist/shell/frame/bridge.js.map +1 -0
  209. package/dist/shell/frame/chromeTheme.d.ts +47 -0
  210. package/dist/shell/frame/chromeTheme.js +118 -0
  211. package/dist/shell/frame/chromeTheme.js.map +1 -0
  212. package/dist/shell/frame/deck.css +209 -0
  213. package/dist/shell/frame/deckStore.d.ts +89 -0
  214. package/dist/shell/frame/deckStore.js +239 -0
  215. package/dist/shell/frame/deckStore.js.map +1 -0
  216. package/dist/shell/frame/devHost.d.ts +35 -0
  217. package/dist/shell/frame/devHost.js +80 -0
  218. package/dist/shell/frame/devHost.js.map +1 -0
  219. package/dist/shell/frame/devModel.d.ts +7 -0
  220. package/dist/shell/frame/devModel.js +17 -0
  221. package/dist/shell/frame/devModel.js.map +1 -0
  222. package/dist/shell/frame/diag.d.ts +7 -0
  223. package/dist/shell/frame/diag.js +39 -0
  224. package/dist/shell/frame/diag.js.map +1 -0
  225. package/dist/shell/frame/edges.css +159 -0
  226. package/dist/shell/frame/findBar.css +14 -0
  227. package/dist/shell/frame/frameMessages.d.ts +248 -0
  228. package/dist/shell/frame/frameMessages.js +252 -0
  229. package/dist/shell/frame/frameMessages.js.map +1 -0
  230. package/dist/shell/frame/hooks.d.ts +39 -0
  231. package/dist/shell/frame/hooks.js +97 -0
  232. package/dist/shell/frame/hooks.js.map +1 -0
  233. package/dist/shell/frame/i18n.d.ts +27 -0
  234. package/dist/shell/frame/i18n.js +66 -0
  235. package/dist/shell/frame/i18n.js.map +1 -0
  236. package/dist/shell/frame/iconPack.d.ts +11 -0
  237. package/dist/shell/frame/iconPack.js +45 -0
  238. package/dist/shell/frame/iconPack.js.map +1 -0
  239. package/dist/shell/frame/icons.d.ts +71 -0
  240. package/dist/shell/frame/icons.js +75 -0
  241. package/dist/shell/frame/icons.js.map +1 -0
  242. package/dist/shell/frame/index.d.ts +34 -0
  243. package/dist/shell/frame/index.js +43 -0
  244. package/dist/shell/frame/index.js.map +1 -0
  245. package/dist/shell/frame/language.d.ts +58 -0
  246. package/dist/shell/frame/language.js +165 -0
  247. package/dist/shell/frame/language.js.map +1 -0
  248. package/dist/shell/frame/mediaModel.d.ts +47 -0
  249. package/dist/shell/frame/mediaModel.js +67 -0
  250. package/dist/shell/frame/mediaModel.js.map +1 -0
  251. package/dist/shell/frame/menuMessages.en.json +96 -0
  252. package/dist/shell/frame/menuModel.d.ts +319 -0
  253. package/dist/shell/frame/menuModel.js +301 -0
  254. package/dist/shell/frame/menuModel.js.map +1 -0
  255. package/dist/shell/frame/nativeMenu.d.ts +5 -0
  256. package/dist/shell/frame/nativeMenu.js +178 -0
  257. package/dist/shell/frame/nativeMenu.js.map +1 -0
  258. package/dist/shell/frame/nativeMenuModel.d.ts +102 -0
  259. package/dist/shell/frame/nativeMenuModel.js +186 -0
  260. package/dist/shell/frame/nativeMenuModel.js.map +1 -0
  261. package/dist/shell/frame/paletteModel.d.ts +139 -0
  262. package/dist/shell/frame/paletteModel.js +114 -0
  263. package/dist/shell/frame/paletteModel.js.map +1 -0
  264. package/dist/shell/frame/paneTheme.css +9 -0
  265. package/dist/shell/frame/pluginCommandStore.d.ts +23 -0
  266. package/dist/shell/frame/pluginCommandStore.js +70 -0
  267. package/dist/shell/frame/pluginCommandStore.js.map +1 -0
  268. package/dist/shell/frame/reportModel.d.ts +52 -0
  269. package/dist/shell/frame/reportModel.js +105 -0
  270. package/dist/shell/frame/reportModel.js.map +1 -0
  271. package/dist/shell/frame/safeStore.d.ts +7 -0
  272. package/dist/shell/frame/safeStore.js +40 -0
  273. package/dist/shell/frame/safeStore.js.map +1 -0
  274. package/dist/shell/frame/searchInput.d.ts +2 -0
  275. package/dist/shell/frame/searchInput.js +11 -0
  276. package/dist/shell/frame/searchInput.js.map +1 -0
  277. package/dist/shell/frame/shell.css +634 -0
  278. package/dist/shell/frame/site.d.ts +206 -0
  279. package/dist/shell/frame/site.js +22 -0
  280. package/dist/shell/frame/site.js.map +1 -0
  281. package/dist/shell/frame/state.d.ts +101 -0
  282. package/dist/shell/frame/state.js +286 -0
  283. package/dist/shell/frame/state.js.map +1 -0
  284. package/dist/shell/frame/syncGate.d.ts +10 -0
  285. package/dist/shell/frame/syncGate.js +36 -0
  286. package/dist/shell/frame/syncGate.js.map +1 -0
  287. package/dist/shell/frame/syncHost.d.ts +35 -0
  288. package/dist/shell/frame/syncHost.js +85 -0
  289. package/dist/shell/frame/syncHost.js.map +1 -0
  290. package/dist/shell/frame/tabStill.d.ts +2 -0
  291. package/dist/shell/frame/tabStill.js +62 -0
  292. package/dist/shell/frame/tabStill.js.map +1 -0
  293. package/dist/shell/frame/themeScopes.d.ts +29 -0
  294. package/dist/shell/frame/themeScopes.js +61 -0
  295. package/dist/shell/frame/themeScopes.js.map +1 -0
  296. package/dist/shell/frame/themeStore.d.ts +99 -0
  297. package/dist/shell/frame/themeStore.js +267 -0
  298. package/dist/shell/frame/themeStore.js.map +1 -0
  299. package/dist/shell/frame/windowBinding.d.ts +2 -0
  300. package/dist/shell/frame/windowBinding.js +7 -0
  301. package/dist/shell/frame/windowBinding.js.map +1 -0
  302. package/dist/shell/frame/workspaceModel.d.ts +82 -0
  303. package/dist/shell/frame/workspaceModel.js +250 -0
  304. package/dist/shell/frame/workspaceModel.js.map +1 -0
  305. package/dist/shell/frame/workspaces.css +84 -0
  306. package/dist/shell/frame/workspaces.d.ts +22 -0
  307. package/dist/shell/frame/workspaces.js +125 -0
  308. package/dist/shell/frame/workspaces.js.map +1 -0
  309. package/dist/shell/frame/zoomStore.d.ts +10 -0
  310. package/dist/shell/frame/zoomStore.js +65 -0
  311. package/dist/shell/frame/zoomStore.js.map +1 -0
  312. package/dist/shell/installController.d.ts +137 -0
  313. package/dist/shell/installController.js +172 -0
  314. package/dist/shell/installController.js.map +1 -0
  315. package/dist/shell/installerMessages.d.ts +30 -0
  316. package/dist/shell/installerMessages.js +36 -0
  317. package/dist/shell/installerMessages.js.map +1 -0
  318. package/dist/shell/linkDrop.js.map +1 -1
  319. package/dist/shell/messages.d.ts +16 -0
  320. package/dist/shell/messages.js +27 -0
  321. package/dist/shell/messages.js.map +1 -0
  322. package/dist/shell/palette.js.map +1 -1
  323. package/dist/shell/paneModel.d.ts +22 -0
  324. package/dist/shell/paneModel.js +24 -1
  325. package/dist/shell/paneModel.js.map +1 -1
  326. package/dist/shell/panel/Appearance.d.ts +8 -0
  327. package/dist/shell/panel/Appearance.js +265 -0
  328. package/dist/shell/panel/Appearance.js.map +1 -0
  329. package/dist/shell/panel/BackupPanel.d.ts +5 -0
  330. package/dist/shell/panel/BackupPanel.js +198 -0
  331. package/dist/shell/panel/BackupPanel.js.map +1 -0
  332. package/dist/shell/panel/DeveloperPanel.d.ts +4 -0
  333. package/dist/shell/panel/DeveloperPanel.js +51 -0
  334. package/dist/shell/panel/DeveloperPanel.js.map +1 -0
  335. package/dist/shell/panel/FeatureToggles.d.ts +13 -0
  336. package/dist/shell/panel/FeatureToggles.js +42 -0
  337. package/dist/shell/panel/FeatureToggles.js.map +1 -0
  338. package/dist/shell/panel/Home.d.ts +3 -0
  339. package/dist/shell/panel/Home.js +23 -0
  340. package/dist/shell/panel/Home.js.map +1 -0
  341. package/dist/shell/panel/IconPackInstall.d.ts +15 -0
  342. package/dist/shell/panel/IconPackInstall.js +41 -0
  343. package/dist/shell/panel/IconPackInstall.js.map +1 -0
  344. package/dist/shell/panel/LanguageSettings.d.ts +1 -0
  345. package/dist/shell/panel/LanguageSettings.js +54 -0
  346. package/dist/shell/panel/LanguageSettings.js.map +1 -0
  347. package/dist/shell/panel/MakePanel.d.ts +3 -0
  348. package/dist/shell/panel/MakePanel.js +237 -0
  349. package/dist/shell/panel/MakePanel.js.map +1 -0
  350. package/dist/shell/panel/MarkdownDoc.d.ts +6 -0
  351. package/dist/shell/panel/MarkdownDoc.js +35 -0
  352. package/dist/shell/panel/MarkdownDoc.js.map +1 -0
  353. package/dist/shell/panel/Modes.d.ts +40 -0
  354. package/dist/shell/panel/Modes.js +270 -0
  355. package/dist/shell/panel/Modes.js.map +1 -0
  356. package/dist/shell/panel/NavIcon.d.ts +4 -0
  357. package/dist/shell/panel/NavIcon.js +6 -0
  358. package/dist/shell/panel/NavIcon.js.map +1 -0
  359. package/dist/shell/panel/Panel.d.ts +7 -0
  360. package/dist/shell/panel/Panel.js +139 -0
  361. package/dist/shell/panel/Panel.js.map +1 -0
  362. package/dist/shell/panel/PluginFeatures.d.ts +24 -0
  363. package/dist/shell/panel/PluginFeatures.js +165 -0
  364. package/dist/shell/panel/PluginFeatures.js.map +1 -0
  365. package/dist/shell/panel/Plugins.d.ts +33 -0
  366. package/dist/shell/panel/Plugins.js +112 -0
  367. package/dist/shell/panel/Plugins.js.map +1 -0
  368. package/dist/shell/panel/PowerSettings.d.ts +4 -0
  369. package/dist/shell/panel/PowerSettings.js +52 -0
  370. package/dist/shell/panel/PowerSettings.js.map +1 -0
  371. package/dist/shell/panel/Settings.d.ts +23 -0
  372. package/dist/shell/panel/Settings.js +117 -0
  373. package/dist/shell/panel/Settings.js.map +1 -0
  374. package/dist/shell/panel/ShareSetup.d.ts +8 -0
  375. package/dist/shell/panel/ShareSetup.js +130 -0
  376. package/dist/shell/panel/ShareSetup.js.map +1 -0
  377. package/dist/shell/panel/StoreSection.d.ts +7 -0
  378. package/dist/shell/panel/StoreSection.js +78 -0
  379. package/dist/shell/panel/StoreSection.js.map +1 -0
  380. package/dist/shell/panel/StringPacks.d.ts +20 -0
  381. package/dist/shell/panel/StringPacks.js +131 -0
  382. package/dist/shell/panel/StringPacks.js.map +1 -0
  383. package/dist/shell/panel/ThemeBuilder.d.ts +5 -0
  384. package/dist/shell/panel/ThemeBuilder.js +205 -0
  385. package/dist/shell/panel/ThemeBuilder.js.map +1 -0
  386. package/dist/shell/panel/backup.css +34 -0
  387. package/dist/shell/panel/builder.css +240 -0
  388. package/dist/shell/panel/builderModel.d.ts +55 -0
  389. package/dist/shell/panel/builderModel.js +95 -0
  390. package/dist/shell/panel/builderModel.js.map +1 -0
  391. package/dist/shell/panel/compare.d.ts +10 -0
  392. package/dist/shell/panel/compare.js +51 -0
  393. package/dist/shell/panel/compare.js.map +1 -0
  394. package/dist/shell/panel/controls.d.ts +135 -0
  395. package/dist/shell/panel/controls.js +213 -0
  396. package/dist/shell/panel/controls.js.map +1 -0
  397. package/dist/shell/panel/featureModel.d.ts +69 -0
  398. package/dist/shell/panel/featureModel.js +79 -0
  399. package/dist/shell/panel/featureModel.js.map +1 -0
  400. package/dist/shell/panel/fonts/FontBrowser.d.ts +10 -0
  401. package/dist/shell/panel/fonts/FontBrowser.js +189 -0
  402. package/dist/shell/panel/fonts/FontBrowser.js.map +1 -0
  403. package/dist/shell/panel/fonts/FontRoles.d.ts +20 -0
  404. package/dist/shell/panel/fonts/FontRoles.js +77 -0
  405. package/dist/shell/panel/fonts/FontRoles.js.map +1 -0
  406. package/dist/shell/panel/fonts/catalog.d.ts +37 -0
  407. package/dist/shell/panel/fonts/catalog.js +68 -0
  408. package/dist/shell/panel/fonts/catalog.js.map +1 -0
  409. package/dist/shell/panel/fonts/googleFontsCatalog.json +1 -0
  410. package/dist/shell/panel/index.d.ts +20 -0
  411. package/dist/shell/panel/index.js +34 -0
  412. package/dist/shell/panel/index.js.map +1 -0
  413. package/dist/shell/panel/languageModel.d.ts +5 -0
  414. package/dist/shell/panel/languageModel.js +7 -0
  415. package/dist/shell/panel/languageModel.js.map +1 -0
  416. package/dist/shell/panel/make.css +73 -0
  417. package/dist/shell/panel/makeModel.d.ts +32 -0
  418. package/dist/shell/panel/makeModel.js +84 -0
  419. package/dist/shell/panel/makeModel.js.map +1 -0
  420. package/dist/shell/panel/markdown.d.ts +46 -0
  421. package/dist/shell/panel/markdown.js +100 -0
  422. package/dist/shell/panel/markdown.js.map +1 -0
  423. package/dist/shell/panel/nav.d.ts +12 -0
  424. package/dist/shell/panel/nav.js +50 -0
  425. package/dist/shell/panel/nav.js.map +1 -0
  426. package/dist/shell/panel/panel.css +401 -0
  427. package/dist/shell/panel/panelMessages.d.ts +803 -0
  428. package/dist/shell/panel/panelMessages.js +779 -0
  429. package/dist/shell/panel/panelMessages.js.map +1 -0
  430. package/dist/shell/panel/plugins.css +59 -0
  431. package/dist/shell/panel/setupModel.d.ts +87 -0
  432. package/dist/shell/panel/setupModel.js +152 -0
  433. package/dist/shell/panel/setupModel.js.map +1 -0
  434. package/dist/shell/panel/site.d.ts +259 -0
  435. package/dist/shell/panel/site.js +25 -0
  436. package/dist/shell/panel/site.js.map +1 -0
  437. package/dist/shell/panel/strings.css +7 -0
  438. package/dist/shell/panel/themes.d.ts +10 -0
  439. package/dist/shell/panel/themes.js +8 -0
  440. package/dist/shell/panel/themes.js.map +1 -0
  441. package/dist/shell/profileModel.d.ts +3 -2
  442. package/dist/shell/profileModel.js +7 -5
  443. package/dist/shell/profileModel.js.map +1 -1
  444. package/dist/shell/store.css +250 -0
  445. package/dist/shell/storeMessages.d.ts +193 -0
  446. package/dist/shell/storeMessages.js +196 -0
  447. package/dist/shell/storeMessages.js.map +1 -0
  448. package/dist/shell/storeModel.d.ts +205 -0
  449. package/dist/shell/storeModel.js +146 -0
  450. package/dist/shell/storeModel.js.map +1 -0
  451. package/dist/shell/stringPacksModel.d.ts +44 -0
  452. package/dist/shell/stringPacksModel.js +99 -0
  453. package/dist/shell/stringPacksModel.js.map +1 -0
  454. package/dist/shell/updateModel.d.ts +2 -1
  455. package/dist/shell/updateModel.js +5 -4
  456. package/dist/shell/updateModel.js.map +1 -1
  457. package/dist/shell/windowControls.d.ts +4 -0
  458. package/dist/shell/windowControls.js +5 -0
  459. package/dist/shell/windowControls.js.map +1 -1
  460. package/i18n-config.schema.json +29 -0
  461. package/i18n-meta.schema.json +26 -0
  462. package/i18n.schema.json +42 -0
  463. package/icons.schema.json +655 -0
  464. package/languages.schema.json +23 -0
  465. package/locales/ar-x-fm.json +11 -0
  466. package/locales/ar.json +1388 -0
  467. package/locales/bg.json +1387 -0
  468. package/locales/bn.json +1387 -0
  469. package/locales/ca.json +1387 -0
  470. package/locales/cs.json +1387 -0
  471. package/locales/da.json +1387 -0
  472. package/locales/de.json +1387 -0
  473. package/locales/el.json +1387 -0
  474. package/locales/en-GB.json +27 -0
  475. package/locales/en.json +1386 -0
  476. package/locales/en.meta.json +51 -0
  477. package/locales/es.json +1387 -0
  478. package/locales/eu.json +1387 -0
  479. package/locales/fa.json +1388 -0
  480. package/locales/fi.json +1387 -0
  481. package/locales/fil.json +1387 -0
  482. package/locales/fr.json +1387 -0
  483. package/locales/ga.json +1387 -0
  484. package/locales/gl.json +1387 -0
  485. package/locales/gu.json +1387 -0
  486. package/locales/ha.json +1387 -0
  487. package/locales/he.json +1388 -0
  488. package/locales/hi.json +1387 -0
  489. package/locales/hr.json +1387 -0
  490. package/locales/hu.json +1387 -0
  491. package/locales/id.json +1387 -0
  492. package/locales/ig.json +1387 -0
  493. package/locales/it.json +1387 -0
  494. package/locales/ja.json +1387 -0
  495. package/locales/kn.json +1387 -0
  496. package/locales/ko.json +1387 -0
  497. package/locales/mr.json +1387 -0
  498. package/locales/ms.json +1387 -0
  499. package/locales/nb.json +1387 -0
  500. package/locales/nl.json +1387 -0
  501. package/locales/pl.json +1387 -0
  502. package/locales/pt.json +1387 -0
  503. package/locales/ro.json +1387 -0
  504. package/locales/ru.json +1387 -0
  505. package/locales/sk.json +1387 -0
  506. package/locales/sr.json +1387 -0
  507. package/locales/sv.json +1387 -0
  508. package/locales/ta.json +1387 -0
  509. package/locales/th.json +1387 -0
  510. package/locales/tr.json +1387 -0
  511. package/locales/uk.json +1387 -0
  512. package/locales/ur.json +1388 -0
  513. package/locales/vi.json +1387 -0
  514. package/locales/yo.json +1387 -0
  515. package/locales/zh-Hans.json +1387 -0
  516. package/locales/zh-Hant.json +1387 -0
  517. package/package.json +138 -5
  518. package/store-catalog.schema.json +78 -0
  519. package/theme.schema.json +4668 -0
  520. package/windows/installer.nsi +946 -0
  521. package/windows/languages/Basque.nsh +28 -0
  522. package/windows/languages/Catalan.nsh +28 -0
  523. package/windows/languages/Croatian.nsh +28 -0
  524. package/windows/languages/Czech.nsh +28 -0
  525. package/windows/languages/Danish.nsh +28 -0
  526. package/windows/languages/Finnish.nsh +28 -0
  527. package/windows/languages/Galician.nsh +28 -0
  528. package/windows/languages/Greek.nsh +28 -0
  529. package/windows/languages/Hungarian.nsh +28 -0
  530. package/windows/languages/Indonesian.nsh +28 -0
  531. package/windows/languages/Irish.nsh +28 -0
  532. package/windows/languages/Malay.nsh +28 -0
  533. package/windows/languages/Polish.nsh +28 -0
  534. package/windows/languages/Romanian.nsh +28 -0
  535. package/windows/languages/Serbian.nsh +28 -0
  536. package/windows/languages/Slovak.nsh +28 -0
  537. package/windows/languages/Thai.nsh +28 -0
@@ -26,7 +26,7 @@ export function redundantNavPanes(panes, isSiteUrl) {
26
26
  const lead = new Map();
27
27
  const redundant = new Set();
28
28
  const ordered = panes
29
- .filter(pane => pane.visible && isSiteUrl(pane.url))
29
+ .filter(pane => pane.visible && pane.role !== 'column' && isSiteUrl(pane.url))
30
30
  .sort((a, b) => a.x - b.x || a.y - b.y || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
31
31
  for (const pane of ordered) {
32
32
  if (lead.has(pane.profile))
@@ -53,4 +53,27 @@ export function withNavRedundant(boxes, isSiteUrl, memory) {
53
53
  memory.delete(id);
54
54
  return items;
55
55
  }
56
+ /**
57
+ * A tab webview's `visible`/`parked` for `tabs_sync`. `shown`: its pane is on screen in the shell;
58
+ * `overlay`: shell overlays open (menus, dialogs, palette, drags); `raiseSupported`: the shell can
59
+ * be raised above the tab webviews for them (`shell_raise`), so panes stay visible under
60
+ * the overlay. Where it cannot, an overlay hides every tab (the shell would draw under them). An
61
+ * overlay never parks (drops to low memory) a tab: only a pane that is not shown is parked.
62
+ */
63
+ export function paneVisibility(pane) {
64
+ return { visible: pane.shown && (pane.raiseSupported || pane.overlay === 0), parked: !pane.shown };
65
+ }
66
+ /** `shell_raise`'s startup probe (`probe`: its answer) unless the developer switch turned raising off. */
67
+ export function raiseSupported(probe, devOff) {
68
+ return probe === true && !devOff;
69
+ }
70
+ /** `[r, g, b]` of a computed CSS color (`rgb(...)`/`rgba(...)`), or null (unparsable or fully transparent). */
71
+ export function cssRgb(color) {
72
+ const parts = /^rgba?\(([^)]+)\)$/.exec(color.trim())?.[1]?.split(/[\s,/]+/).filter(Boolean).map(Number);
73
+ if (!parts || parts.length < 3 || parts.slice(0, 3).some(n => !Number.isFinite(n)))
74
+ return null;
75
+ if (parts.length > 3 && parts[3] === 0)
76
+ return null;
77
+ return [0, 1, 2].map(i => Math.max(0, Math.min(255, Math.round(parts[i]))));
78
+ }
56
79
  //# sourceMappingURL=paneModel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paneModel.js","sourceRoot":"","sources":["../../../shell/src/paneModel.ts"],"names":[],"mappings":"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","sourcesContent":["// Pane geometry rules for the dock: where a link opened \"beside\" a pane goes, and which site panes\n// repeat a navigation rail already on screen. Two site panes of the same account side by side (or\n// stacked) both draw the site's rail; only the leftmost (then topmost) one needs it. Panes of\n// different accounts keep theirs: the rail's account button is the only in-page sign of which\n// account a pane is.\n\nexport type PaneBox = { id: string; url: string; profile: string; x: number; y: number; visible: boolean };\n\n/** `besideOf`: the source group ids whose \"beside\" links this group's tabs were opened for. */\nexport type GroupBox = { id: string; left: number; top: number; right: number; bottom: number; besideOf?: readonly string[] };\n\n/**\n * Where a link opened \"beside\" a pane goes: the side pane this source opened before (so repeated\n * links reuse one), when it is still to its right and shares some of its height; else null to split\n * a new one. A group the user opened themselves (another feed, another account) is never taken over.\n */\nexport function besideGroup(source: GroupBox, groups: readonly GroupBox[]): string | null {\n let best: GroupBox | null = null;\n for (const group of groups) {\n if (group.id === source.id || !group.besideOf?.includes(source.id)) continue;\n const overlap = Math.min(group.bottom, source.bottom) - Math.max(group.top, source.top);\n if (group.left < source.right - 4 || overlap <= 0) continue;\n if (!best || group.left < best.left || (group.left === best.left && group.top < best.top)) best = group;\n }\n return best?.id ?? null;\n}\n\n/** Ids of visible site panes whose navigation duplicates the leftmost site pane of the same account. */\nexport function redundantNavPanes(panes: readonly PaneBox[], isSiteUrl: (url: string) => boolean): Set<string> {\n const lead = new Map<string, PaneBox>();\n const redundant = new Set<string>();\n const ordered = panes\n .filter(pane => pane.visible && isSiteUrl(pane.url))\n .sort((a, b) => a.x - b.x || a.y - b.y || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n for (const pane of ordered) {\n if (lead.has(pane.profile)) redundant.add(pane.id);\n else lead.set(pane.profile, pane);\n }\n return redundant;\n}\n\n/**\n * The `navRedundant` flag per tab for `tabs_sync`. Only visible panes are judged (a shell overlay\n * hides them all and so changes nothing); a hidden tab keeps its last value (`memory`) so it shows\n * up again without a flicker. Tabs that are gone are forgotten.\n */\nexport function withNavRedundant<T extends PaneBox>(boxes: readonly T[], isSiteUrl: (url: string) => boolean, memory: Map<string, boolean>): Array<T & { navRedundant: boolean }> {\n const redundant = redundantNavPanes(boxes, isSiteUrl);\n const items = boxes.map(box => {\n if (box.visible) memory.set(box.id, redundant.has(box.id));\n return { ...box, navRedundant: memory.get(box.id) ?? false };\n });\n for (const id of memory.keys()) if (!boxes.some(box => box.id === id)) memory.delete(id);\n return items;\n}\n"]}
1
+ {"version":3,"file":"paneModel.js","sourceRoot":"","sources":["../../../../../shell/src/paneModel.ts"],"names":[],"mappings":"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","sourcesContent":["// Pane geometry rules for the dock: where a link opened \"beside\" a pane goes, and which site panes\n// repeat a navigation rail already on screen. Two site panes of the same account side by side (or\n// stacked) both draw the site's rail; only the leftmost (then topmost) one needs it. Panes of\n// different accounts keep theirs: the rail's account button is the only in-page sign of which\n// account a pane is.\n\n/** `role`: 'column' boxes are deck columns (Power User Mode); they hide the site's chrome themselves\n * and never take part in the rail rules. Missing = an ordinary pane. */\nexport type PaneBox = { id: string; url: string; profile: string; x: number; y: number; visible: boolean; role?: 'pane' | 'column' };\n\n/** `besideOf`: the source group ids whose \"beside\" links this group's tabs were opened for. */\nexport type GroupBox = { id: string; left: number; top: number; right: number; bottom: number; besideOf?: readonly string[] };\n\n/**\n * Where a link opened \"beside\" a pane goes: the side pane this source opened before (so repeated\n * links reuse one), when it is still to its right and shares some of its height; else null to split\n * a new one. A group the user opened themselves (another feed, another account) is never taken over.\n */\nexport function besideGroup(source: GroupBox, groups: readonly GroupBox[]): string | null {\n let best: GroupBox | null = null;\n for (const group of groups) {\n if (group.id === source.id || !group.besideOf?.includes(source.id)) continue;\n const overlap = Math.min(group.bottom, source.bottom) - Math.max(group.top, source.top);\n if (group.left < source.right - 4 || overlap <= 0) continue;\n if (!best || group.left < best.left || (group.left === best.left && group.top < best.top)) best = group;\n }\n return best?.id ?? null;\n}\n\n/** Ids of visible site panes whose navigation duplicates the leftmost site pane of the same account. */\nexport function redundantNavPanes(panes: readonly PaneBox[], isSiteUrl: (url: string) => boolean): Set<string> {\n const lead = new Map<string, PaneBox>();\n const redundant = new Set<string>();\n const ordered = panes\n .filter(pane => pane.visible && pane.role !== 'column' && isSiteUrl(pane.url))\n .sort((a, b) => a.x - b.x || a.y - b.y || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n for (const pane of ordered) {\n if (lead.has(pane.profile)) redundant.add(pane.id);\n else lead.set(pane.profile, pane);\n }\n return redundant;\n}\n\n/**\n * The `navRedundant` flag per tab for `tabs_sync`. Only visible panes are judged (a shell overlay\n * hides them all and so changes nothing); a hidden tab keeps its last value (`memory`) so it shows\n * up again without a flicker. Tabs that are gone are forgotten.\n */\nexport function withNavRedundant<T extends PaneBox>(boxes: readonly T[], isSiteUrl: (url: string) => boolean, memory: Map<string, boolean>): Array<T & { navRedundant: boolean }> {\n const redundant = redundantNavPanes(boxes, isSiteUrl);\n const items = boxes.map(box => {\n if (box.visible) memory.set(box.id, redundant.has(box.id));\n return { ...box, navRedundant: memory.get(box.id) ?? false };\n });\n for (const id of memory.keys()) if (!boxes.some(box => box.id === id)) memory.delete(id);\n return items;\n}\n\n/**\n * A tab webview's `visible`/`parked` for `tabs_sync`. `shown`: its pane is on screen in the shell;\n * `overlay`: shell overlays open (menus, dialogs, palette, drags); `raiseSupported`: the shell can\n * be raised above the tab webviews for them (`shell_raise`), so panes stay visible under\n * the overlay. Where it cannot, an overlay hides every tab (the shell would draw under them). An\n * overlay never parks (drops to low memory) a tab: only a pane that is not shown is parked.\n */\nexport function paneVisibility(pane: { shown: boolean; overlay: number; raiseSupported: boolean }): { visible: boolean; parked: boolean } {\n return { visible: pane.shown && (pane.raiseSupported || pane.overlay === 0), parked: !pane.shown };\n}\n\n/** `shell_raise`'s startup probe (`probe`: its answer) unless the developer switch turned raising off. */\nexport function raiseSupported(probe: unknown, devOff: boolean): boolean {\n return probe === true && !devOff;\n}\n\n/** `[r, g, b]` of a computed CSS color (`rgb(...)`/`rgba(...)`), or null (unparsable or fully transparent). */\nexport function cssRgb(color: string): [number, number, number] | null {\n const parts = /^rgba?\\(([^)]+)\\)$/.exec(color.trim())?.[1]?.split(/[\\s,/]+/).filter(Boolean).map(Number);\n if (!parts || parts.length < 3 || parts.slice(0, 3).some(n => !Number.isFinite(n))) return null;\n if (parts.length > 3 && parts[3] === 0) return null;\n return [0, 1, 2].map(i => Math.max(0, Math.min(255, Math.round(parts[i]!)))) as [number, number, number];\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { type ThemeSpec } from '../../runtime/themeSpec.ts';
2
+ import { type Notify } from './site.ts';
3
+ import './builder.css';
4
+ /** Built-in themes have translated descriptions (`theme.<id>.description` in the app's catalog); imported ones keep their own. */
5
+ export declare const themeDescription: (theme: ThemeSpec) => string;
6
+ export declare function Appearance({ notify }: {
7
+ notify: Notify;
8
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,265 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // Appearance: the theme gallery (live previews rendered from each theme document), per-group
3
+ // customization on top of the selected theme (fonts per role with the Google Fonts browser),
4
+ // account and pane themes, downloaded fonts, import/export of theme JSON and Custom CSS. The theme
5
+ // documents, the store and the miniature are the app's (`PanelSite.themes`).
6
+ import { useEffect, useRef, useState } from 'react';
7
+ import { THEME_SCHEMA_URL } from "../../runtime/themeApi.js";
8
+ import { FONT_CHOICES, MAX_IMAGE_CHARS, fontChoiceOf, googleFontsUsed, parseThemeJson, slug, } from "../../runtime/themeSpec.js";
9
+ import { AccountAvatar, accountName, useProfiles } from "../frame/AccountSwitcher.js";
10
+ import { useT } from "../frame/hooks.js";
11
+ import { formatDate, t, tx } from "../frame/i18n.js";
12
+ import { ThemeDots } from "../frame/PaneTheme.js";
13
+ import { shell } from "../frame/state.js";
14
+ import { assign } from "../frame/themeScopes.js";
15
+ import { tabProfile } from "../profileModel.js";
16
+ import { Badge, Button, ColorField, Row, Section, Segmented, Select, Slider, Toggle, useSettingsQuery } from "./controls.js";
17
+ import { IconPackImport, IconPackReview } from "./IconPackInstall.js";
18
+ import { themeDoctor } from "../../runtime/themeDoctor.js";
19
+ import { bytesLabel, defaultWeights, loadCatalog, weightsLabel } from "./fonts/catalog.js";
20
+ import { FontRoles } from "./fonts/FontRoles.js";
21
+ import { CustomCssEditor } from "./Plugins.js";
22
+ import { panelSite, panelThemes } from "./site.js";
23
+ import { useThemeState } from "./themes.js";
24
+ import './builder.css';
25
+ const getError = (error) => error instanceof Error ? error.message : String(error);
26
+ const CORNERS = [
27
+ { value: 'square', label: 'wb.appearance.corners.square', radius: 0, button: 0 },
28
+ { value: 'crisp', label: 'wb.appearance.corners.crisp', radius: 5, button: 5 },
29
+ { value: 'soft', label: 'wb.appearance.corners.soft', radius: 12, button: 10 },
30
+ { value: 'round', label: 'wb.appearance.corners.round', radius: 16, button: 9999 },
31
+ ];
32
+ const backgrounds = () => [
33
+ { value: 'none', label: t('wb.appearance.bg.none') }, { value: 'glow', label: t('wb.appearance.bg.glow') }, { value: 'dots', label: t('wb.appearance.bg.dots') }, { value: 'grid', label: t('wb.appearance.bg.grid') },
34
+ { value: 'diagonal', label: t('wb.appearance.bg.diagonal') }, { value: 'scanlines', label: t('wb.appearance.bg.scanlines') }, { value: 'paper', label: t('wb.appearance.bg.paper') },
35
+ { value: 'clouds', label: t('wb.appearance.bg.clouds') }, { value: 'image', label: t('wb.appearance.bg.image'), hint: t('wb.appearance.bg.imageHint') },
36
+ ];
37
+ const modeLabel = (theme) => theme.mode === 'auto' ? t('wb.appearance.mode.auto') : theme.mode === 'light' ? t('wb.appearance.mode.light') : t('wb.appearance.mode.dark');
38
+ const fontLabel = (theme) => {
39
+ const family = theme.font.family;
40
+ const choices = panelThemes().fontChoices ?? FONT_CHOICES;
41
+ const choice = choices.find(item => item.id === fontChoiceOf(family, choices));
42
+ return (choice?.key ? tx(choice.key, undefined, choice.label) : choice?.label) ?? family[0] ?? panelThemes().siteFont;
43
+ };
44
+ /** Built-in themes have translated descriptions (`theme.<id>.description` in the app's catalog); imported ones keep their own. */
45
+ export const themeDescription = (theme) => tx(`theme.${theme.id}.description`, undefined, theme.description);
46
+ const formatPercent = (value) => t('wb.appearance.percent', { value: value / 100 });
47
+ const hasOverrides = (choice) => !!choice.accent || Object.keys(choice.overrides).length > 0;
48
+ function download(name, text) {
49
+ const url = URL.createObjectURL(new Blob([text], { type: 'application/json' }));
50
+ const anchor = document.createElement('a');
51
+ anchor.href = url;
52
+ anchor.download = name;
53
+ anchor.click();
54
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
55
+ }
56
+ function backgroundFor(kind, theme, image) {
57
+ const base = panelThemes().draftColors;
58
+ const text = theme.colors?.text ?? '#8b98a5';
59
+ const light = theme.mode === 'light';
60
+ switch (kind) {
61
+ case 'none': return { kind: 'none' };
62
+ case 'glow': return { kind: 'gradient', from: theme.colors?.page ?? theme.colors?.bg ?? base.bg, to: theme.colors?.page ?? theme.colors?.bg ?? base.bg, angle: 180, glow: theme.colors?.accent ?? base.accent };
63
+ case 'image': return { kind: 'image', url: image ?? '', fit: 'cover', dim: light ? 0.55 : 0.6 };
64
+ case 'clouds': return { kind: 'pattern', pattern: 'clouds', ink: light ? '#ffffff' : text, opacity: light ? 0.55 : 0.07, size: 220 };
65
+ case 'dots': return { kind: 'pattern', pattern: 'dots', ink: text, opacity: 0.16, size: 18 };
66
+ case 'grid': return { kind: 'pattern', pattern: 'grid', ink: text, opacity: 0.06, size: 28 };
67
+ case 'diagonal': return { kind: 'pattern', pattern: 'diagonal', ink: text, opacity: 0.06, size: 10 };
68
+ case 'scanlines': return { kind: 'pattern', pattern: 'scanlines', ink: theme.colors?.accent ?? text, opacity: 0.05, size: 4 };
69
+ case 'paper': return { kind: 'pattern', pattern: 'paper', ink: light ? '#7a6a50' : text, opacity: 0.1, size: 180 };
70
+ }
71
+ }
72
+ const backgroundChoice = (background) => background.kind === 'none' ? 'none' : background.kind === 'gradient' ? 'glow' : background.kind === 'image' ? 'image' : background.pattern;
73
+ /** Asks the panel to show another section (the Theme Builder). */
74
+ const openSection = (section) => window.dispatchEvent(new CustomEvent('bt-panel-section', { detail: section }));
75
+ export function Appearance({ notify }) {
76
+ const t = useT();
77
+ const themes = panelThemes();
78
+ const { allThemes, installFont, missingFonts, setChoice, setScopes } = themes.store;
79
+ const ThemePreview = themes.Preview;
80
+ const { ready, choice, scopes } = useThemeState();
81
+ const [importing, setImporting] = useState(false);
82
+ const [asking, setAsking] = useState(null);
83
+ const [packReview, setPackReview] = useState(null);
84
+ const query = useSettingsQuery();
85
+ if (!ready)
86
+ return null;
87
+ const effective = themes.catalog.resolve(choice);
88
+ const base = themes.catalog.base(choice);
89
+ const all = allThemes(choice);
90
+ const siteTheme = themes.catalog.defaultChoice.preset;
91
+ const suffix = themes.fileSuffix ?? '.theme.json';
92
+ const update = (next, commit = true) => setChoice(next, commit).catch(error => notify(getError(error), true));
93
+ const override = (patch, commit = true) => {
94
+ const overrides = { ...choice.overrides };
95
+ for (const [key, value] of Object.entries(patch)) {
96
+ overrides[key] = key === 'background' ? value : { ...choice.overrides[key], ...value };
97
+ }
98
+ return update({ ...choice, overrides }, commit);
99
+ };
100
+ const setRole = (role, next, commit = true) => override({ font: { roles: { ...(choice.overrides.font?.roles ?? {}), [role]: next } } }, commit);
101
+ function select(id) {
102
+ if (id === choice.preset)
103
+ return;
104
+ // Customizations belong to the theme they were made on; switching starts clean.
105
+ void update({ ...choice, preset: id, overrides: {}, accent: null });
106
+ }
107
+ function remove(theme) {
108
+ const themes = choice.themes.filter(item => item.id !== theme.id);
109
+ void update({ ...choice, themes, ...(choice.preset === theme.id ? { preset: siteTheme, overrides: {}, accent: null } : {}) }).then(() => notify(t('wb.appearance.removedTheme', { name: theme.name })));
110
+ }
111
+ function add(theme, message) {
112
+ let id = theme.id;
113
+ for (let n = 2; all.some(item => item.id === id); n++)
114
+ id = `${theme.id.slice(0, 36)}-${n}`;
115
+ void update({ ...choice, themes: [...choice.themes, { ...theme, id }], preset: id, overrides: {}, accent: null }).then(() => notify(message));
116
+ }
117
+ function exportTheme() {
118
+ const custom = hasOverrides(choice);
119
+ const doc = { ...effective, ...(custom ? { id: slug(`${effective.name} custom`), name: t('wb.appearance.customName', { name: effective.name }) } : {}) };
120
+ // `$schema` lets editors validate and complete the file; imports ignore it.
121
+ download(`${doc.id}${suffix}`, JSON.stringify({ $schema: THEME_SCHEMA_URL, ...doc }, null, 2));
122
+ }
123
+ function saveAsNew() {
124
+ const name = t('wb.appearance.savedName', { name: base.name });
125
+ add({ ...effective, id: slug(`${base.name} custom`), name, author: t('wb.appearance.you'), description: t('wb.appearance.basedOn', { name: base.name }) }, t('wb.appearance.saved', { name }));
126
+ }
127
+ /** An imported theme that names Google fonts asks before anything is downloaded. */
128
+ function imported(theme, warnings) {
129
+ setImporting(false);
130
+ add(theme, `${t('wb.appearance.imported', { name: theme.name })}${warnings.length ? ` ${warnings.join(' ')}` : ''}`);
131
+ const families = missingFonts(theme);
132
+ if (families.length)
133
+ setAsking({ theme, families });
134
+ }
135
+ async function downloadFonts(families) {
136
+ setAsking(null);
137
+ const catalog = await loadCatalog();
138
+ for (const family of families) {
139
+ const font = catalog.find(item => item.family === family);
140
+ try {
141
+ await installFont(family, font ? defaultWeights(font) : { kind: 'list', values: [400, 700] });
142
+ notify(t('wb.appearance.downloadedFont', { family }));
143
+ }
144
+ catch (error) {
145
+ notify(`${family}: ${getError(error)}`, true);
146
+ }
147
+ }
148
+ }
149
+ const cornerValue = CORNERS.find(corner => corner.radius === effective.shape.radius && corner.button === effective.shape.button)?.value ?? null;
150
+ const timeline = effective.layout.cards ? 'cards' : effective.layout.frame ? 'framed' : 'flat';
151
+ async function pickImage(file) {
152
+ if (!file)
153
+ return;
154
+ if (!/^image\/(png|jpeg|webp|gif|avif)$/.test(file.type)) {
155
+ notify(t('wb.appearance.imageType'), true);
156
+ return;
157
+ }
158
+ const url = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(String(reader.result)); reader.onerror = () => reject(reader.error); reader.readAsDataURL(file); });
159
+ if (url.length > MAX_IMAGE_CHARS) {
160
+ notify(t('wb.appearance.imageTooLarge'), true);
161
+ return;
162
+ }
163
+ void override({ background: backgroundFor('image', effective, url) });
164
+ }
165
+ const searching = !!query;
166
+ return _jsxs(_Fragment, { children: [!searching && _jsxs(Section, { title: t('wb.appearance.theme'), id: "themes", hint: t('wb.appearance.themeHint'), action: _jsxs("div", { className: "bt-inline", children: [_jsx(Button, { size: "sm", tone: "ghost", onClick: () => setImporting(!importing), icon: _jsx(Glyph, { d: "M8 2v8m0 0L5 7m3 3 3-3M3 13h10" }), children: t('wb.common.import') }), _jsx(Button, { size: "sm", tone: "ghost", onClick: exportTheme, icon: _jsx(Glyph, { d: "M8 11V3m0 0L5 6m3-3 3 3M3 13h10" }), children: t('wb.common.export') }), _jsx(Button, { size: "sm", tone: "primary", onClick: () => openSection('builder'), icon: _jsx(Glyph, { d: "M3 13l.6-2.6L10.5 3.5l2 2-6.9 6.9zM9 5l2 2" }), children: t('wb.panel.section.builder') })] }), children: [importing && _jsx(ImportPanel, { onCancel: () => setImporting(false), onImport: imported }), asking && _jsx("div", { className: "bt-import wb-ask", role: "alertdialog", "aria-label": t('wb.appearance.askFonts'), children: _jsxs("div", { className: "bt-import-drop", children: [_jsx("strong", { children: t('wb.appearance.askFontsTitle', { name: asking.theme.name, fonts: asking.families.join(', ') }) }), _jsx("p", { children: t('wb.appearance.askFontsText', { count: asking.families.length }) }), _jsxs("div", { className: "bt-inline", children: [_jsx(Button, { size: "sm", tone: "primary", onClick: () => void downloadFonts(asking.families), children: t('wb.panel.updates.download') }), _jsx(Button, { size: "sm", tone: "ghost", onClick: () => setAsking(null), children: t('wb.common.notNow') })] })] }) }), _jsx("div", { className: "bt-gallery", role: "radiogroup", "aria-label": t('wb.appearance.theme'), children: all.map(theme => {
167
+ const on = theme.id === choice.preset;
168
+ const isImported = choice.themes.some(item => item.id === theme.id);
169
+ return _jsxs("div", { className: `bt-theme ${on ? 'is-on' : ''}`, children: [_jsxs("button", { type: "button", role: "radio", "aria-checked": on, className: "bt-theme-hit", onClick: () => select(theme.id), "aria-label": `${theme.name}. ${themeDescription(theme)}`, children: [_jsx(ThemePreview, { theme: on ? effective : theme }), _jsxs("span", { className: "bt-theme-info", children: [_jsxs("span", { className: "bt-theme-title", children: [_jsx("strong", { children: theme.name }), on && _jsx("span", { className: "bt-theme-check", "aria-hidden": "true", children: _jsx(Glyph, { d: "m4 8.5 2.5 2.5L12 5.5" }) })] }), _jsx("small", { children: themeDescription(theme) }), _jsxs("span", { className: "bt-theme-tags", children: [_jsx("em", { children: modeLabel(theme) }), _jsx("em", { children: fontLabel(theme) }), theme.layout.cards && _jsx("em", { children: t('wb.appearance.timeline.cards') }), googleFontsUsed(theme).length > 0 && _jsx("em", { children: "Google Fonts" }), isImported && _jsx("em", { className: "is-accent", children: t('wb.appearance.yours') }), theme.css && _jsx("em", { children: "CSS" })] })] })] }), isImported && _jsx("button", { type: "button", className: "bt-theme-remove", "aria-label": t('wb.appearance.removeNamed', { name: theme.name }), title: t('wb.appearance.removeTheme'), onClick: () => remove(theme), children: _jsx(Glyph, { d: "m4.5 4.5 7 7m0-7-7 7" }) })] }, theme.id);
170
+ }) })] }), _jsxs(Section, { title: searching ? t('wb.appearance.theme') : t('wb.appearance.customize', { name: base.name }), id: "customize", hint: searching ? undefined : t('wb.appearance.customizeHint'), action: !searching && hasOverrides(choice) ? _jsxs("div", { className: "bt-inline", children: [_jsx(Button, { size: "sm", tone: "ghost", onClick: () => void update({ ...choice, overrides: {}, accent: null }), children: t('wb.common.reset') }), _jsx(Button, { size: "sm", onClick: saveAsNew, children: t('wb.appearance.saveAsTheme') })] }) : undefined, children: [_jsx(Row, { label: t('wb.appearance.accent'), hint: t('wb.appearance.accentHint'), keywords: "color colour highlight link", wide: true, children: _jsx(ColorField, { label: t('wb.appearance.accentColor'), value: choice.accent, swatches: [...themes.accents], autoLabel: t('wb.appearance.theme'), onChange: accent => void update({ ...choice, accent }) }) }), themes.iconPacks?.length ? _jsx(Row, { label: t('wb.appearance.icons'), hint: t('wb.appearance.iconsHint'), keywords: "icon pack glyphs symbols pixel import", wide: true, children: _jsxs("div", { className: "wb-pack-row", children: [_jsxs("div", { className: "bt-inline", children: [_jsx(Select, { label: t('wb.appearance.icons'), value: choice.icons ?? 'theme', width: 220, onChange: icons => void update({ ...choice, icons: icons === 'theme' ? undefined : icons }), options: [{ value: 'theme', label: t('wb.appearance.icons.theme') }, { value: 'site', label: t('wb.appearance.icons.site') }, ...themes.iconPacks.filter(pack => !choice.packs?.some(item => item.id === pack.id)).map(pack => ({ value: pack.id, label: pack.name })), ...(choice.packs ?? []).map(pack => ({ value: pack.id, label: pack.name }))] }), _jsx(IconPackImport, { onError: message => notify(message, true), onParsed: (pack, warnings, bytes) => setPackReview({ pack, warnings, bytes }) })] }), choice.packs?.length ? _jsx("div", { className: "bt-inline wb-pack-list", "aria-label": t('wb.appearance.icons.imported'), children: choice.packs.map(pack => _jsx(Button, { size: "sm", tone: "ghost", onClick: () => void update({ ...choice, packs: choice.packs.filter(item => item.id !== pack.id), ...(choice.icons === pack.id ? { icons: undefined } : {}) }).then(() => notify(t('wb.appearance.icons.removed', { name: pack.name }))), children: t('wb.appearance.icons.remove', { name: pack.name }) }, pack.id)) }) : null, packReview && _jsx(IconPackReview, { ...packReview, replaces: !!choice.packs?.some(item => item.id === packReview.pack.id), onCancel: () => setPackReview(null), onInstall: () => { const { pack } = packReview; setPackReview(null); void update({ ...choice, packs: [...(choice.packs ?? []).filter(item => item.id !== pack.id), pack], icons: pack.id }).then(() => notify(t('wb.appearance.icons.installed', { name: pack.name }))); } })] }) }) : null, _jsx(Row, { label: t('wb.appearance.fonts'), hint: t('wb.appearance.fontsHint'), keywords: "typeface typography family font google fonts post text heading numbers code interface window dialogs", wide: true, children: _jsx(FontRoles, { font: effective.font, onRole: setRole, compact: true }) }), _jsx(Row, { label: t('wb.appearance.textSize'), hint: t('wb.appearance.textSizeHint'), keywords: "font scale bigger smaller zoom", children: _jsx(Slider, { label: t('wb.appearance.textSize'), min: 85, max: 120, value: Math.round(effective.font.scale * 100), format: v => formatPercent(v), onChange: v => void override({ font: { scale: v / 100 } }, false), onCommit: v => void override({ font: { scale: v / 100 } }) }) }), _jsx(Row, { label: t('wb.appearance.bold'), hint: t('wb.appearance.boldHint'), keywords: "font weight heavy", children: _jsx(Segmented, { label: t('wb.appearance.bold'), size: "sm", value: effective.font.bold >= 750 ? 800 : effective.font.bold >= 675 ? 700 : 600, onChange: bold => void override({ font: { bold } }), options: [{ value: 600, label: t('wb.appearance.bold.medium') }, { value: 700, label: t('wb.appearance.bold.bold') }, { value: 800, label: t('wb.appearance.bold.heavy') }] }) }), _jsx(Row, { label: t('wb.appearance.corners'), hint: t('wb.appearance.cornersHint'), keywords: "radius rounded square shape", children: _jsx(Segmented, { label: t('wb.appearance.corners'), size: "sm", value: cornerValue, onChange: value => { const corner = CORNERS.find(item => item.value === value); void override({ shape: { radius: corner.radius, button: corner.button } }); }, options: CORNERS.map(corner => ({ value: corner.value, label: t(corner.label) })) }) }), _jsx(Row, { label: t('wb.appearance.avatars'), keywords: "profile picture shape", children: _jsx(Segmented, { label: t('wb.appearance.avatars'), size: "sm", value: effective.shape.avatar, onChange: avatar => void override({ shape: { avatar } }), options: [{ value: 'circle', label: t('wb.appearance.avatars.circle') }, { value: 'rounded', label: t('wb.appearance.avatars.rounded') }, { value: 'square', label: t('wb.appearance.corners.square') }] }) }), _jsx(Row, { label: t('wb.appearance.density'), hint: t('wb.appearance.densityHint'), keywords: "compact spacing padding", children: _jsx(Segmented, { label: t('wb.appearance.density'), size: "sm", value: effective.layout.density, onChange: density => void override({ layout: { density } }), options: [{ value: 'compact', label: t('wb.appearance.density.compact') }, { value: 'default', label: t('wb.appearance.density.default') }, { value: 'comfortable', label: t('wb.appearance.density.roomy') }] }) }), _jsx(Row, { label: t('wb.appearance.timeline'), hint: t('wb.appearance.timelineHint'), keywords: "cards layout frame", children: _jsx(Segmented, { label: t('wb.appearance.timelineStyle'), size: "sm", value: timeline, onChange: value => void override({ layout: { cards: value === 'cards', frame: value === 'framed' } }), options: [{ value: 'flat', label: t('wb.appearance.timeline.flat') }, { value: 'framed', label: t('wb.appearance.timeline.framed') }, { value: 'cards', label: t('wb.appearance.timeline.cards') }] }) }), _jsx(Row, { label: t('wb.appearance.timelineWidth'), keywords: "column layout wide narrow", children: _jsx(Slider, { label: t('wb.appearance.timelineWidth'), min: 520, max: 820, step: 10, value: effective.layout.column, format: v => t('wb.appearance.px', { value: v }), onChange: column => void override({ layout: { column } }, false), onCommit: column => void override({ layout: { column } }) }) }), _jsx(Row, { label: t('wb.appearance.sidebarWidth'), keywords: "column layout trends", children: _jsx(Slider, { label: t('wb.appearance.sidebarWidth'), min: 290, max: 400, step: 10, value: effective.layout.sidebar, format: v => t('wb.appearance.px', { value: v }), onChange: sidebar => void override({ layout: { sidebar } }, false), onCommit: sidebar => void override({ layout: { sidebar } }) }) }), _jsx(Row, { label: t('wb.appearance.background'), hint: t('wb.appearance.backgroundHint'), keywords: "wallpaper pattern image photo canvas", children: _jsxs("div", { className: "bt-inline", children: [_jsx(Select, { label: t('wb.appearance.background'), value: backgroundChoice(effective.background), options: backgrounds(), width: 170, onChange: kind => { if (kind === 'image')
171
+ document.getElementById('bt-bg-file')?.click();
172
+ else
173
+ void override({ background: backgroundFor(kind, effective) }); } }), _jsx("input", { id: "bt-bg-file", type: "file", hidden: true, accept: "image/png,image/jpeg,image/webp,image/gif,image/avif", onChange: event => { void pickImage(event.target.files?.[0]); event.target.value = ''; } })] }) }), effective.background.kind === 'image' && _jsx(Row, { label: t('wb.appearance.dim'), hint: t('wb.appearance.dimHint'), keywords: "background image", children: _jsx(Slider, { label: t('wb.appearance.dim'), min: 35, max: 95, value: Math.round(effective.background.dim * 100), format: v => formatPercent(v), onChange: v => void override({ background: { ...effective.background, dim: v / 100 } }, false), onCommit: v => void override({ background: { ...effective.background, dim: v / 100 } }) }) }), _jsx(Row, { label: t('wb.appearance.motion'), hint: t('wb.appearance.motionHint'), keywords: "animation transition", children: _jsx(Segmented, { label: t('wb.appearance.motion'), size: "sm", value: effective.effects.motion === 0 ? 0 : effective.effects.motion < 200 ? 140 : 260, onChange: motion => void override({ effects: { motion } }), options: [{ value: 0, label: t('wb.common.off') }, { value: 140, label: t('wb.appearance.motion.subtle') }, { value: 260, label: t('wb.appearance.motion.lively') }] }) }), _jsx(Row, { label: t('wb.appearance.hover'), hint: t('wb.appearance.hoverHint'), keywords: "effect highlight lift glow", children: _jsx(Segmented, { label: t('wb.appearance.hoverEffect'), size: "sm", value: effective.effects.hover, onChange: hover => void override({ effects: { hover } }), options: [{ value: 'none', label: t('wb.appearance.hover.none') }, { value: 'tint', label: t('wb.appearance.hover.tint') }, { value: 'lift', label: t('wb.appearance.hover.lift') }, { value: 'glow', label: t('wb.appearance.bg.glow') }] }) }), _jsx(Row, { label: t('wb.appearance.crt'), hint: t('wb.appearance.crtHint'), keywords: "retro terminal effect", children: _jsx(Toggle, { label: t('wb.appearance.crt'), checked: effective.effects.crt, onChange: crt => void override({ effects: { crt } }) }) }), _jsx(ThemeCssEditor, { css: effective.css, onApply: text => { void override({ css: { text } }); notify(t('wb.appearance.cssApplied', { name: base.name })); } }, choice.preset)] }), _jsx(DoctorReport, { theme: effective }), _jsxs(Section, { title: t('wb.appearance.scopes'), id: "theme-scopes", hint: searching ? undefined : t('wb.appearance.scopesHint'), children: [_jsx(Row, { label: t('wb.appearance.chrome'), hint: t('wb.appearance.chromeHint'), keywords: "chrome window tabs titlebar panel colors own style", children: _jsx(Toggle, { label: t('wb.appearance.chrome'), checked: scopes.chrome === 'theme', onChange: on => void setScopes({ ...scopes, chrome: on ? 'theme' : 'own' }).catch(error => notify(getError(error), true)) }) }), _jsx(AccountThemes, { notify: notify }), _jsx(PaneThemes, { notify: notify })] }), _jsx(DownloadedFonts, { notify: notify }), (panelSite().appearance?.extra ?? []).map((Extra, index) => _jsx(Extra, { notify: notify, openSection: id => window.dispatchEvent(new CustomEvent('bt-panel-section', { detail: id })) }, index)), _jsx(CustomCssEditor, { notify: notify })] });
174
+ }
175
+ /** Theme choices for a scope row: follow (the level above) plus every theme with its swatch. */
176
+ /** The theme doctor's full report on the theme as it is now: every finding, where it is, what it found, how to fix it. Advice only. */
177
+ function DoctorReport({ theme }) {
178
+ const t = useT();
179
+ const advice = themeDoctor(theme);
180
+ const words = (item, part) => t(`wb.doctor.${item.key}.${part}`, item.params);
181
+ return _jsx(Section, { title: t('wb.doctor.title'), id: "theme-doctor", hint: t('wb.doctor.hint'), action: _jsx(Badge, { tone: advice.length ? undefined : 'ok', children: t('wb.doctor.count', { count: advice.length }) }), children: advice.length === 0
182
+ ? _jsx("p", { className: "btp-hint", children: t('wb.doctor.empty') })
183
+ : _jsx("ul", { className: "bt-doctor", "aria-label": t('wb.doctor.title'), children: advice.map((item, index) => _jsxs("li", { className: `bt-doctor-item is-${item.kind}`, children: [_jsxs("span", { className: "bt-doctor-head", children: [_jsx(Badge, { children: t(`wb.doctor.kind.${item.kind}`) }), _jsx("strong", { children: words(item, 'found') })] }), _jsxs("small", { className: "bt-doctor-line", children: [t('wb.doctor.where'), ": ", _jsx("code", { children: item.where })] }), _jsxs("small", { className: "bt-doctor-line", children: [t('wb.doctor.fix'), ": ", words(item, 'fix')] })] }, `${item.id}:${item.where}:${index}`)) }) });
184
+ }
185
+ function scopeOptions(follow) {
186
+ // Called during render of components that use useT(), so the labels follow the language.
187
+ return [{ value: '', label: follow }, ...panelThemes().store.allThemes().map(theme => ({ value: theme.id, label: theme.name, icon: _jsx(ThemeDots, { theme: theme }) }))];
188
+ }
189
+ function AccountThemes({ notify }) {
190
+ const t = useT();
191
+ const { setScopes, themeName, themeState } = panelThemes().store;
192
+ const profiles = useProfiles();
193
+ const { scopes, choice } = useThemeState();
194
+ return _jsx(Row, { label: t('wb.panel.section.accounts'), hint: t('wb.appearance.accountsHint'), keywords: "account profile per account theme login", wide: true, children: _jsx("div", { className: "wb-scope-list", children: profiles.profiles.map(profile => _jsxs("div", { className: "wb-scope", children: [_jsxs("span", { className: "wb-scope-who", children: [_jsx(AccountAvatar, { profile: profile, size: 26 }), _jsxs("span", { children: [_jsx("b", { children: accountName(profile) }), _jsx("small", { children: scopes.profiles[profile.id] ? t('wb.appearance.ownTheme') : t('wb.appearance.followsApp', { name: themeName(choice.preset) }) })] })] }), _jsx(Select, { label: t('wb.appearance.themeFor', { name: accountName(profile) }), value: scopes.profiles[profile.id] ?? '', width: 210, options: scopeOptions(t('wb.appearance.followApp')), onChange: id => void setScopes(assign(themeState().scopes, 'profiles', profile.id, id || null)).catch(error => notify(getError(error), true)) })] }, profile.id)) }) });
195
+ }
196
+ /** Open site panes, each with the theme it shows and where that comes from. */
197
+ function PaneThemes({ notify }) {
198
+ const t = useT();
199
+ const { setScopes, tabTheme, themeName, themeState } = panelThemes().store;
200
+ const { scopes } = useThemeState();
201
+ const [, refresh] = useState(0);
202
+ useEffect(() => {
203
+ const api = shell.api;
204
+ if (!api)
205
+ return;
206
+ const bump = () => refresh(n => n + 1);
207
+ const subs = [api.onDidAddPanel(bump), api.onDidRemovePanel(bump), api.onDidLayoutChange(bump)];
208
+ return () => subs.forEach(sub => sub.dispose());
209
+ }, []);
210
+ const panes = (shell.api?.panels ?? []).filter(panel => panel.params?.kind === 'web');
211
+ return _jsx(Row, { label: t('wb.appearance.panes'), hint: panes.length ? t('wb.appearance.panesHint') : t('wb.appearance.panesEmpty'), keywords: "pane split tab per pane theme", wide: true, children: panes.length > 0 && _jsx("div", { className: "wb-scope-list", children: panes.map(panel => {
212
+ const params = panel.params;
213
+ const profile = tabProfile(shell.profiles, params.profile);
214
+ const current = tabTheme({ id: panel.id, profile: profile.id });
215
+ return _jsxs("div", { className: "wb-scope", children: [_jsxs("span", { className: "wb-scope-who", children: [_jsx(ThemeDots, { theme: current.theme }), _jsxs("span", { children: [_jsx("b", { children: panel.api.title || params.url }), _jsxs("small", { children: [accountName(profile), " \u00B7 ", current.source === 'pane' ? t('wb.appearance.ownTheme') : current.source === 'account' ? t('wb.appearance.accountTheme', { name: themeName(current.id) }) : t('wb.appearance.appTheme', { name: themeName(current.id) })] })] })] }), _jsx(Select, { label: t('wb.appearance.themeFor', { name: panel.api.title || t('wb.appearance.pane') }), value: scopes.panes[panel.id] ?? '', width: 210, options: scopeOptions(t('wb.appearance.followAccount')), onChange: id => void setScopes(assign(themeState().scopes, 'panes', panel.id, id || null)).catch(error => notify(getError(error), true)) })] }, panel.id);
216
+ }) }) });
217
+ }
218
+ function DownloadedFonts({ notify }) {
219
+ const t = useT();
220
+ const { removeFont } = panelThemes().store;
221
+ const { fonts } = useThemeState();
222
+ const query = useSettingsQuery();
223
+ const title = t('wb.appearance.downloaded');
224
+ if (query && !`downloaded fonts google fonts typeface remove storage ${title}`.toLowerCase().includes(query.toLowerCase().trim()))
225
+ return null;
226
+ const total = fonts.reduce((sum, font) => sum + font.bytes, 0);
227
+ return _jsx(Section, { title: title, id: "fonts", hint: fonts.length ? t('wb.appearance.downloadedHint', { count: fonts.length, size: bytesLabel(total) }) : t('wb.appearance.downloadedEmpty'), children: _jsx(Row, { label: fonts.length ? t('wb.appearance.families') : t('wb.appearance.noneYet'), hint: t('wb.appearance.familiesHint'), keywords: "google fonts downloaded remove", wide: true, children: fonts.length > 0 && _jsx("ul", { className: "wb-fontlist", children: fonts.map(font => _jsxs("li", { children: [_jsxs("span", { children: [_jsx("b", { style: { fontFamily: `"${font.family}", system-ui` }, children: font.family }), _jsx("br", {}), _jsxs("small", { children: [weightsLabel(font.weights), " \u00B7 ", bytesLabel(font.bytes)] })] }), _jsx("small", { children: formatDate(font.installedAt, { dateStyle: 'medium' }) }), _jsx(Button, { size: "sm", tone: "ghost", onClick: () => void removeFont(font.family).then(() => notify(t('wb.appearance.removedFont', { family: font.family }))).catch(error => notify(getError(error), true)), children: t('wb.common.remove') })] }, font.family)) }) }) });
228
+ }
229
+ /** The selected theme's own CSS: travels with the theme (export, Save as theme); switching themes starts clean, like every customization. */
230
+ function ThemeCssEditor({ css, onApply }) {
231
+ const t = useT();
232
+ const [text, setText] = useState(css);
233
+ const query = useSettingsQuery();
234
+ useEffect(() => setText(css), [css]);
235
+ const label = t('wb.appearance.themeCss');
236
+ if (query && !`theme css stylesheet style code custom ${label}`.toLowerCase().includes(query.toLowerCase().trim()))
237
+ return null;
238
+ const dirty = text !== css;
239
+ return _jsx(Row, { label: label, hint: t('wb.appearance.themeCssHint'), keywords: "css stylesheet style code custom", wide: true, children: _jsxs("div", { className: "bt-code is-compact", style: { width: '100%' }, children: [_jsx("textarea", { "aria-label": t('wb.appearance.themeCssLabel'), spellCheck: false, value: text, placeholder: panelSite().cssExamples?.theme ?? '/* CSS that travels with this theme */', onChange: event => setText(event.target.value), onKeyDown: event => { if ((event.ctrlKey || event.metaKey) && event.key === 's') {
240
+ event.preventDefault();
241
+ if (dirty)
242
+ onApply(text);
243
+ } } }), _jsxs("div", { className: "bt-code-bar", children: [_jsx("small", { children: t('wb.appearance.cssLines', { count: text.split('\n').length }) }), dirty && _jsx(Button, { size: "sm", tone: "ghost", onClick: () => setText(css), children: t('wb.common.discard') }), _jsx(Button, { size: "sm", tone: "primary", disabled: !dirty, onClick: () => onApply(text), children: t('wb.common.apply') })] })] }) });
244
+ }
245
+ function Glyph({ d }) {
246
+ return _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", "aria-hidden": "true", children: _jsx("path", { d: d, fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
247
+ }
248
+ function ImportPanel({ onImport, onCancel }) {
249
+ const t = useT();
250
+ const [text, setText] = useState('');
251
+ const [error, setError] = useState('');
252
+ const file = useRef(null);
253
+ const run = (json) => {
254
+ const parsed = parseThemeJson(json);
255
+ if ('error' in parsed) {
256
+ setError(parsed.error);
257
+ return;
258
+ }
259
+ // The theme doctor: advice only (never a block); contrast is already in the warnings.
260
+ const hints = themeDoctor(parsed.theme).filter(advice => advice.kind !== 'contrast');
261
+ onImport(parsed.theme, hints.length ? [...parsed.warnings, t('wb.appearance.doctorHints', { count: hints.length, hint: t(`wb.doctor.${hints[0].key}.found`, hints[0].params) })] : parsed.warnings);
262
+ };
263
+ return _jsxs("div", { className: "bt-import", children: [_jsxs("div", { className: "bt-import-drop", onDragOver: event => event.preventDefault(), onDrop: event => { event.preventDefault(); void event.dataTransfer.files[0]?.text().then(run); }, children: [_jsx("strong", { children: t('wb.appearance.importTitle') }), _jsx("p", { children: t('wb.appearance.importText') }), _jsxs("div", { className: "bt-inline", children: [_jsx(Button, { size: "sm", tone: "primary", onClick: () => file.current?.click(), children: t('wb.common.chooseFile') }), _jsx(Button, { size: "sm", tone: "ghost", onClick: onCancel, children: t('wb.common.cancel') })] }), _jsx("input", { ref: file, type: "file", hidden: true, accept: "application/json,.json", onChange: event => { void event.target.files?.[0]?.text().then(run); event.target.value = ''; } })] }), _jsxs("div", { className: "bt-code is-compact", children: [_jsx("textarea", { "aria-label": t('wb.appearance.themeJson'), spellCheck: false, placeholder: `${t('wb.appearance.pasteJson')}\n{ "name": "My theme", "colors": { … } }`, value: text, onChange: event => { setText(event.target.value); setError(''); } }), _jsxs("div", { className: "bt-code-bar", children: [error ? _jsx("small", { className: "is-error", role: "alert", children: error }) : _jsx("small", { children: t('wb.appearance.importSafe') }), _jsx(Button, { size: "sm", disabled: !text.trim(), onClick: () => run(text), children: t('wb.appearance.importJson') })] })] })] });
264
+ }
265
+ //# sourceMappingURL=Appearance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Appearance.js","sourceRoot":"","sources":["../../../../../../shell/src/panel/Appearance.tsx"],"names":[],"mappings":"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","sourcesContent":["// Appearance: the theme gallery (live previews rendered from each theme document), per-group\n// customization on top of the selected theme (fonts per role with the Google Fonts browser),\n// account and pane themes, downloaded fonts, import/export of theme JSON and Custom CSS. The theme\n// documents, the store and the miniature are the app's (`PanelSite.themes`).\nimport { useEffect, useRef, useState } from 'react';\nimport { THEME_SCHEMA_URL } from '../../../runtime/src/themeApi.ts';\nimport type { ThemeChoice } from '../../../runtime/src/themeChoice.ts';\nimport {\n FONT_CHOICES, MAX_IMAGE_CHARS, fontChoiceOf, googleFontsUsed, parseThemeJson, slug,\n type Background, type FontRole, type FontRoleName, type Pattern, type ThemeOverrides, type ThemeSpec,\n} from '../../../runtime/src/themeSpec.ts';\nimport { AccountAvatar, accountName, useProfiles } from '../frame/AccountSwitcher.tsx';\nimport { useT } from '../frame/hooks.ts';\nimport { formatDate, t, tx } from '../frame/i18n.ts';\nimport { ThemeDots } from '../frame/PaneTheme.tsx';\nimport { shell, type WebParams } from '../frame/state.ts';\nimport { assign } from '../frame/themeScopes.ts';\nimport { tabProfile } from '../profileModel.ts';\nimport { Badge, Button, ColorField, Row, Section, Segmented, Select, Slider, Toggle, useSettingsQuery, type Option } from './controls.tsx';\nimport { IconPackImport, IconPackReview } from './IconPackInstall.tsx';\nimport type { IconPack } from '../../../runtime/src/themeIcons.ts';\nimport { themeDoctor, type DoctorAdvice } from '../../../runtime/src/themeDoctor.ts';\nimport { bytesLabel, defaultWeights, loadCatalog, weightsLabel } from './fonts/catalog.ts';\nimport { FontRoles } from './fonts/FontRoles.tsx';\nimport { CustomCssEditor } from './Plugins.tsx';\nimport { panelSite, panelThemes, type Notify } from './site.ts';\nimport { useThemeState } from './themes.ts';\nimport './builder.css';\n\nconst getError = (error: unknown) => error instanceof Error ? error.message : String(error);\n\nconst CORNERS = [\n { value: 'square', label: 'wb.appearance.corners.square', radius: 0, button: 0 },\n { value: 'crisp', label: 'wb.appearance.corners.crisp', radius: 5, button: 5 },\n { value: 'soft', label: 'wb.appearance.corners.soft', radius: 12, button: 10 },\n { value: 'round', label: 'wb.appearance.corners.round', radius: 16, button: 9999 },\n] as const;\ntype BackgroundChoice = 'none' | 'glow' | Pattern | 'image';\nconst backgrounds = (): Array<Option<BackgroundChoice>> => [\n { value: 'none', label: t('wb.appearance.bg.none') }, { value: 'glow', label: t('wb.appearance.bg.glow') }, { value: 'dots', label: t('wb.appearance.bg.dots') }, { value: 'grid', label: t('wb.appearance.bg.grid') },\n { value: 'diagonal', label: t('wb.appearance.bg.diagonal') }, { value: 'scanlines', label: t('wb.appearance.bg.scanlines') }, { value: 'paper', label: t('wb.appearance.bg.paper') },\n { value: 'clouds', label: t('wb.appearance.bg.clouds') }, { value: 'image', label: t('wb.appearance.bg.image'), hint: t('wb.appearance.bg.imageHint') },\n];\n\nconst modeLabel = (theme: ThemeSpec) => theme.mode === 'auto' ? t('wb.appearance.mode.auto') : theme.mode === 'light' ? t('wb.appearance.mode.light') : t('wb.appearance.mode.dark');\nconst fontLabel = (theme: ThemeSpec) => {\n const family = theme.font.family;\n const choices = panelThemes().fontChoices ?? FONT_CHOICES;\n const choice = choices.find(item => item.id === fontChoiceOf(family, choices));\n return (choice?.key ? tx(choice.key, undefined, choice.label) : choice?.label) ?? family[0] ?? panelThemes().siteFont;\n};\n/** Built-in themes have translated descriptions (`theme.<id>.description` in the app's catalog); imported ones keep their own. */\nexport const themeDescription = (theme: ThemeSpec) => tx(`theme.${theme.id}.description`, undefined, theme.description);\nconst formatPercent = (value: number) => t('wb.appearance.percent', { value: value / 100 });\nconst hasOverrides = (choice: ThemeChoice) => !!choice.accent || Object.keys(choice.overrides).length > 0;\n\nfunction download(name: string, text: string) {\n const url = URL.createObjectURL(new Blob([text], { type: 'application/json' }));\n const anchor = document.createElement('a');\n anchor.href = url; anchor.download = name; anchor.click();\n setTimeout(() => URL.revokeObjectURL(url), 1000);\n}\n\nfunction backgroundFor(kind: BackgroundChoice, theme: ThemeSpec, image?: string): Background {\n const base = panelThemes().draftColors;\n const text = theme.colors?.text ?? '#8b98a5';\n const light = theme.mode === 'light';\n switch (kind) {\n case 'none': return { kind: 'none' };\n case 'glow': return { kind: 'gradient', from: theme.colors?.page ?? theme.colors?.bg ?? base.bg, to: theme.colors?.page ?? theme.colors?.bg ?? base.bg, angle: 180, glow: theme.colors?.accent ?? base.accent };\n case 'image': return { kind: 'image', url: image ?? '', fit: 'cover', dim: light ? 0.55 : 0.6 };\n case 'clouds': return { kind: 'pattern', pattern: 'clouds', ink: light ? '#ffffff' : text, opacity: light ? 0.55 : 0.07, size: 220 };\n case 'dots': return { kind: 'pattern', pattern: 'dots', ink: text, opacity: 0.16, size: 18 };\n case 'grid': return { kind: 'pattern', pattern: 'grid', ink: text, opacity: 0.06, size: 28 };\n case 'diagonal': return { kind: 'pattern', pattern: 'diagonal', ink: text, opacity: 0.06, size: 10 };\n case 'scanlines': return { kind: 'pattern', pattern: 'scanlines', ink: theme.colors?.accent ?? text, opacity: 0.05, size: 4 };\n case 'paper': return { kind: 'pattern', pattern: 'paper', ink: light ? '#7a6a50' : text, opacity: 0.1, size: 180 };\n }\n}\nconst backgroundChoice = (background: Background): BackgroundChoice =>\n background.kind === 'none' ? 'none' : background.kind === 'gradient' ? 'glow' : background.kind === 'image' ? 'image' : background.pattern;\n\n/** Asks the panel to show another section (the Theme Builder). */\nconst openSection = (section: string) => window.dispatchEvent(new CustomEvent('bt-panel-section', { detail: section }));\n\nexport function Appearance({ notify }: { notify: Notify }) {\n const t = useT();\n const themes = panelThemes();\n const { allThemes, installFont, missingFonts, setChoice, setScopes } = themes.store;\n const ThemePreview = themes.Preview;\n const { ready, choice, scopes } = useThemeState();\n const [importing, setImporting] = useState(false);\n const [asking, setAsking] = useState<{ theme: ThemeSpec; families: string[] } | null>(null);\n const [packReview, setPackReview] = useState<{ pack: IconPack; warnings: string[]; bytes: number } | null>(null);\n const query = useSettingsQuery();\n\n if (!ready) return null;\n const effective = themes.catalog.resolve(choice);\n const base = themes.catalog.base(choice);\n const all = allThemes(choice);\n const siteTheme = themes.catalog.defaultChoice.preset;\n const suffix = themes.fileSuffix ?? '.theme.json';\n\n const update = (next: ThemeChoice, commit = true) => setChoice(next, commit).catch(error => notify(getError(error), true));\n const override = (patch: ThemeOverrides, commit = true) => {\n const overrides: ThemeOverrides = { ...choice.overrides };\n for (const [key, value] of Object.entries(patch) as Array<[keyof ThemeOverrides, unknown]>) {\n (overrides as Record<string, unknown>)[key] = key === 'background' ? value : { ...(choice.overrides[key] as object | undefined), ...(value as object) };\n }\n return update({ ...choice, overrides }, commit);\n };\n const setRole = (role: FontRoleName, next: FontRole, commit = true) =>\n override({ font: { roles: { ...(choice.overrides.font?.roles ?? {}), [role]: next } } }, commit);\n\n function select(id: string) {\n if (id === choice.preset) return;\n // Customizations belong to the theme they were made on; switching starts clean.\n void update({ ...choice, preset: id, overrides: {}, accent: null });\n }\n function remove(theme: ThemeSpec) {\n const themes = choice.themes.filter(item => item.id !== theme.id);\n void update({ ...choice, themes, ...(choice.preset === theme.id ? { preset: siteTheme, overrides: {}, accent: null } : {}) }).then(() => notify(t('wb.appearance.removedTheme', { name: theme.name })));\n }\n function add(theme: ThemeSpec, message: string) {\n let id = theme.id;\n for (let n = 2; all.some(item => item.id === id); n++) id = `${theme.id.slice(0, 36)}-${n}`;\n void update({ ...choice, themes: [...choice.themes, { ...theme, id }], preset: id, overrides: {}, accent: null }).then(() => notify(message));\n }\n function exportTheme() {\n const custom = hasOverrides(choice);\n const doc: ThemeSpec = { ...effective, ...(custom ? { id: slug(`${effective.name} custom`), name: t('wb.appearance.customName', { name: effective.name }) } : {}) };\n // `$schema` lets editors validate and complete the file; imports ignore it.\n download(`${doc.id}${suffix}`, JSON.stringify({ $schema: THEME_SCHEMA_URL, ...doc }, null, 2));\n }\n function saveAsNew() {\n const name = t('wb.appearance.savedName', { name: base.name });\n add({ ...effective, id: slug(`${base.name} custom`), name, author: t('wb.appearance.you'), description: t('wb.appearance.basedOn', { name: base.name }) }, t('wb.appearance.saved', { name }));\n }\n /** An imported theme that names Google fonts asks before anything is downloaded. */\n function imported(theme: ThemeSpec, warnings: string[]) {\n setImporting(false);\n add(theme, `${t('wb.appearance.imported', { name: theme.name })}${warnings.length ? ` ${warnings.join(' ')}` : ''}`);\n const families = missingFonts(theme);\n if (families.length) setAsking({ theme, families });\n }\n async function downloadFonts(families: string[]) {\n setAsking(null);\n const catalog = await loadCatalog();\n for (const family of families) {\n const font = catalog.find(item => item.family === family);\n try {\n await installFont(family, font ? defaultWeights(font) : { kind: 'list', values: [400, 700] });\n notify(t('wb.appearance.downloadedFont', { family }));\n } catch (error) { notify(`${family}: ${getError(error)}`, true); }\n }\n }\n\n const cornerValue = CORNERS.find(corner => corner.radius === effective.shape.radius && corner.button === effective.shape.button)?.value ?? null;\n const timeline = effective.layout.cards ? 'cards' : effective.layout.frame ? 'framed' : 'flat';\n\n async function pickImage(file: File | undefined) {\n if (!file) return;\n if (!/^image\\/(png|jpeg|webp|gif|avif)$/.test(file.type)) { notify(t('wb.appearance.imageType'), true); return; }\n const url = await new Promise<string>((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(String(reader.result)); reader.onerror = () => reject(reader.error); reader.readAsDataURL(file); });\n if (url.length > MAX_IMAGE_CHARS) { notify(t('wb.appearance.imageTooLarge'), true); return; }\n void override({ background: backgroundFor('image', effective, url) });\n }\n\n const searching = !!query;\n return <>\n {!searching && <Section title={t('wb.appearance.theme')} id=\"themes\" hint={t('wb.appearance.themeHint')}\n action={<div className=\"bt-inline\">\n <Button size=\"sm\" tone=\"ghost\" onClick={() => setImporting(!importing)} icon={<Glyph d=\"M8 2v8m0 0L5 7m3 3 3-3M3 13h10\"/>}>{t('wb.common.import')}</Button>\n <Button size=\"sm\" tone=\"ghost\" onClick={exportTheme} icon={<Glyph d=\"M8 11V3m0 0L5 6m3-3 3 3M3 13h10\"/>}>{t('wb.common.export')}</Button>\n <Button size=\"sm\" tone=\"primary\" onClick={() => openSection('builder')} icon={<Glyph d=\"M3 13l.6-2.6L10.5 3.5l2 2-6.9 6.9zM9 5l2 2\"/>}>{t('wb.panel.section.builder')}</Button>\n </div>}>\n {importing && <ImportPanel onCancel={() => setImporting(false)} onImport={imported}/>}\n {asking && <div className=\"bt-import wb-ask\" role=\"alertdialog\" aria-label={t('wb.appearance.askFonts')}>\n <div className=\"bt-import-drop\">\n <strong>{t('wb.appearance.askFontsTitle', { name: asking.theme.name, fonts: asking.families.join(', ') })}</strong>\n <p>{t('wb.appearance.askFontsText', { count: asking.families.length })}</p>\n <div className=\"bt-inline\"><Button size=\"sm\" tone=\"primary\" onClick={() => void downloadFonts(asking.families)}>{t('wb.panel.updates.download')}</Button><Button size=\"sm\" tone=\"ghost\" onClick={() => setAsking(null)}>{t('wb.common.notNow')}</Button></div>\n </div>\n </div>}\n <div className=\"bt-gallery\" role=\"radiogroup\" aria-label={t('wb.appearance.theme')}>\n {all.map(theme => {\n const on = theme.id === choice.preset;\n const isImported = choice.themes.some(item => item.id === theme.id);\n return <div key={theme.id} className={`bt-theme ${on ? 'is-on' : ''}`}>\n <button type=\"button\" role=\"radio\" aria-checked={on} className=\"bt-theme-hit\" onClick={() => select(theme.id)} aria-label={`${theme.name}. ${themeDescription(theme)}`}>\n <ThemePreview theme={on ? effective : theme}/>\n <span className=\"bt-theme-info\">\n <span className=\"bt-theme-title\"><strong>{theme.name}</strong>{on && <span className=\"bt-theme-check\" aria-hidden=\"true\"><Glyph d=\"m4 8.5 2.5 2.5L12 5.5\"/></span>}</span>\n <small>{themeDescription(theme)}</small>\n <span className=\"bt-theme-tags\"><em>{modeLabel(theme)}</em><em>{fontLabel(theme)}</em>{theme.layout.cards && <em>{t('wb.appearance.timeline.cards')}</em>}{googleFontsUsed(theme).length > 0 && <em>Google Fonts</em>}{isImported && <em className=\"is-accent\">{t('wb.appearance.yours')}</em>}{theme.css && <em>CSS</em>}</span>\n </span>\n </button>\n {isImported && <button type=\"button\" className=\"bt-theme-remove\" aria-label={t('wb.appearance.removeNamed', { name: theme.name })} title={t('wb.appearance.removeTheme')} onClick={() => remove(theme)}><Glyph d=\"m4.5 4.5 7 7m0-7-7 7\"/></button>}\n </div>;\n })}\n </div>\n </Section>}\n\n <Section title={searching ? t('wb.appearance.theme') : t('wb.appearance.customize', { name: base.name })} id=\"customize\"\n hint={searching ? undefined : t('wb.appearance.customizeHint')}\n action={!searching && hasOverrides(choice) ? <div className=\"bt-inline\">\n <Button size=\"sm\" tone=\"ghost\" onClick={() => void update({ ...choice, overrides: {}, accent: null })}>{t('wb.common.reset')}</Button>\n <Button size=\"sm\" onClick={saveAsNew}>{t('wb.appearance.saveAsTheme')}</Button>\n </div> : undefined}>\n <Row label={t('wb.appearance.accent')} hint={t('wb.appearance.accentHint')} keywords=\"color colour highlight link\" wide>\n <ColorField label={t('wb.appearance.accentColor')} value={choice.accent} swatches={[...themes.accents]} autoLabel={t('wb.appearance.theme')} onChange={accent => void update({ ...choice, accent })}/>\n </Row>\n {themes.iconPacks?.length ? <Row label={t('wb.appearance.icons')} hint={t('wb.appearance.iconsHint')} keywords=\"icon pack glyphs symbols pixel import\" wide>\n <div className=\"wb-pack-row\"><div className=\"bt-inline\">\n <Select label={t('wb.appearance.icons')} value={choice.icons ?? 'theme'} width={220}\n onChange={icons => void update({ ...choice, icons: icons === 'theme' ? undefined : icons })}\n options={[{ value: 'theme', label: t('wb.appearance.icons.theme') }, { value: 'site', label: t('wb.appearance.icons.site') }, ...themes.iconPacks.filter(pack => !choice.packs?.some(item => item.id === pack.id)).map(pack => ({ value: pack.id, label: pack.name })), ...(choice.packs ?? []).map(pack => ({ value: pack.id, label: pack.name }))]}/>\n <IconPackImport onError={message => notify(message, true)} onParsed={(pack, warnings, bytes) => setPackReview({ pack, warnings, bytes })}/>\n </div>\n {choice.packs?.length ? <div className=\"bt-inline wb-pack-list\" aria-label={t('wb.appearance.icons.imported')}>{choice.packs.map(pack => <Button key={pack.id} size=\"sm\" tone=\"ghost\" onClick={() => void update({ ...choice, packs: choice.packs!.filter(item => item.id !== pack.id), ...(choice.icons === pack.id ? { icons: undefined } : {}) }).then(() => notify(t('wb.appearance.icons.removed', { name: pack.name })))}>{t('wb.appearance.icons.remove', { name: pack.name })}</Button>)}</div> : null}\n {packReview && <IconPackReview {...packReview} replaces={!!choice.packs?.some(item => item.id === packReview.pack.id)} onCancel={() => setPackReview(null)}\n onInstall={() => { const { pack } = packReview; setPackReview(null); void update({ ...choice, packs: [...(choice.packs ?? []).filter(item => item.id !== pack.id), pack], icons: pack.id }).then(() => notify(t('wb.appearance.icons.installed', { name: pack.name }))); }}/>}</div>\n </Row> : null}\n <Row label={t('wb.appearance.fonts')} hint={t('wb.appearance.fontsHint')}\n keywords=\"typeface typography family font google fonts post text heading numbers code interface window dialogs\" wide>\n <FontRoles font={effective.font} onRole={setRole} compact/>\n </Row>\n <Row label={t('wb.appearance.textSize')} hint={t('wb.appearance.textSizeHint')} keywords=\"font scale bigger smaller zoom\">\n <Slider label={t('wb.appearance.textSize')} min={85} max={120} value={Math.round(effective.font.scale * 100)} format={v => formatPercent(v)}\n onChange={v => void override({ font: { scale: v / 100 } }, false)} onCommit={v => void override({ font: { scale: v / 100 } })}/>\n </Row>\n <Row label={t('wb.appearance.bold')} hint={t('wb.appearance.boldHint')} keywords=\"font weight heavy\">\n <Segmented label={t('wb.appearance.bold')} size=\"sm\" value={effective.font.bold >= 750 ? 800 : effective.font.bold >= 675 ? 700 : 600}\n onChange={bold => void override({ font: { bold } })} options={[{ value: 600, label: t('wb.appearance.bold.medium') }, { value: 700, label: t('wb.appearance.bold.bold') }, { value: 800, label: t('wb.appearance.bold.heavy') }]}/>\n </Row>\n <Row label={t('wb.appearance.corners')} hint={t('wb.appearance.cornersHint')} keywords=\"radius rounded square shape\">\n <Segmented label={t('wb.appearance.corners')} size=\"sm\" value={cornerValue} onChange={value => { const corner = CORNERS.find(item => item.value === value)!; void override({ shape: { radius: corner.radius, button: corner.button } }); }}\n options={CORNERS.map(corner => ({ value: corner.value, label: t(corner.label) }))}/>\n </Row>\n <Row label={t('wb.appearance.avatars')} keywords=\"profile picture shape\">\n <Segmented label={t('wb.appearance.avatars')} size=\"sm\" value={effective.shape.avatar} onChange={avatar => void override({ shape: { avatar } })}\n options={[{ value: 'circle', label: t('wb.appearance.avatars.circle') }, { value: 'rounded', label: t('wb.appearance.avatars.rounded') }, { value: 'square', label: t('wb.appearance.corners.square') }]}/>\n </Row>\n <Row label={t('wb.appearance.density')} hint={t('wb.appearance.densityHint')} keywords=\"compact spacing padding\">\n <Segmented label={t('wb.appearance.density')} size=\"sm\" value={effective.layout.density} onChange={density => void override({ layout: { density } })}\n options={[{ value: 'compact', label: t('wb.appearance.density.compact') }, { value: 'default', label: t('wb.appearance.density.default') }, { value: 'comfortable', label: t('wb.appearance.density.roomy') }]}/>\n </Row>\n <Row label={t('wb.appearance.timeline')} hint={t('wb.appearance.timelineHint')} keywords=\"cards layout frame\">\n <Segmented label={t('wb.appearance.timelineStyle')} size=\"sm\" value={timeline} onChange={value => void override({ layout: { cards: value === 'cards', frame: value === 'framed' } })}\n options={[{ value: 'flat', label: t('wb.appearance.timeline.flat') }, { value: 'framed', label: t('wb.appearance.timeline.framed') }, { value: 'cards', label: t('wb.appearance.timeline.cards') }]}/>\n </Row>\n <Row label={t('wb.appearance.timelineWidth')} keywords=\"column layout wide narrow\">\n <Slider label={t('wb.appearance.timelineWidth')} min={520} max={820} step={10} value={effective.layout.column} format={v => t('wb.appearance.px', { value: v })}\n onChange={column => void override({ layout: { column } }, false)} onCommit={column => void override({ layout: { column } })}/>\n </Row>\n <Row label={t('wb.appearance.sidebarWidth')} keywords=\"column layout trends\">\n <Slider label={t('wb.appearance.sidebarWidth')} min={290} max={400} step={10} value={effective.layout.sidebar} format={v => t('wb.appearance.px', { value: v })}\n onChange={sidebar => void override({ layout: { sidebar } }, false)} onCommit={sidebar => void override({ layout: { sidebar } })}/>\n </Row>\n <Row label={t('wb.appearance.background')} hint={t('wb.appearance.backgroundHint')} keywords=\"wallpaper pattern image photo canvas\">\n <div className=\"bt-inline\">\n <Select label={t('wb.appearance.background')} value={backgroundChoice(effective.background)} options={backgrounds()} width={170}\n onChange={kind => { if (kind === 'image') document.getElementById('bt-bg-file')?.click(); else void override({ background: backgroundFor(kind, effective) }); }}/>\n <input id=\"bt-bg-file\" type=\"file\" hidden accept=\"image/png,image/jpeg,image/webp,image/gif,image/avif\" onChange={event => { void pickImage(event.target.files?.[0]); event.target.value = ''; }}/>\n </div>\n </Row>\n {effective.background.kind === 'image' && <Row label={t('wb.appearance.dim')} hint={t('wb.appearance.dimHint')} keywords=\"background image\">\n <Slider label={t('wb.appearance.dim')} min={35} max={95} value={Math.round(effective.background.dim * 100)} format={v => formatPercent(v)}\n onChange={v => void override({ background: { ...(effective.background as Extract<Background, { kind: 'image' }>), dim: v / 100 } }, false)}\n onCommit={v => void override({ background: { ...(effective.background as Extract<Background, { kind: 'image' }>), dim: v / 100 } })}/>\n </Row>}\n <Row label={t('wb.appearance.motion')} hint={t('wb.appearance.motionHint')} keywords=\"animation transition\">\n <Segmented label={t('wb.appearance.motion')} size=\"sm\" value={effective.effects.motion === 0 ? 0 : effective.effects.motion < 200 ? 140 : 260} onChange={motion => void override({ effects: { motion } })}\n options={[{ value: 0, label: t('wb.common.off') }, { value: 140, label: t('wb.appearance.motion.subtle') }, { value: 260, label: t('wb.appearance.motion.lively') }]}/>\n </Row>\n <Row label={t('wb.appearance.hover')} hint={t('wb.appearance.hoverHint')} keywords=\"effect highlight lift glow\">\n <Segmented label={t('wb.appearance.hoverEffect')} size=\"sm\" value={effective.effects.hover} onChange={hover => void override({ effects: { hover } })}\n options={[{ value: 'none', label: t('wb.appearance.hover.none') }, { value: 'tint', label: t('wb.appearance.hover.tint') }, { value: 'lift', label: t('wb.appearance.hover.lift') }, { value: 'glow', label: t('wb.appearance.bg.glow') }]}/>\n </Row>\n <Row label={t('wb.appearance.crt')} hint={t('wb.appearance.crtHint')} keywords=\"retro terminal effect\">\n <Toggle label={t('wb.appearance.crt')} checked={effective.effects.crt} onChange={crt => void override({ effects: { crt } })}/>\n </Row>\n <ThemeCssEditor key={choice.preset} css={effective.css} onApply={text => { void override({ css: { text } }); notify(t('wb.appearance.cssApplied', { name: base.name })); }}/>\n </Section>\n\n <DoctorReport theme={effective}/>\n\n <Section title={t('wb.appearance.scopes')} id=\"theme-scopes\" hint={searching ? undefined : t('wb.appearance.scopesHint')}>\n <Row label={t('wb.appearance.chrome')} hint={t('wb.appearance.chromeHint')}\n keywords=\"chrome window tabs titlebar panel colors own style\">\n <Toggle label={t('wb.appearance.chrome')} checked={scopes.chrome === 'theme'} onChange={on => void setScopes({ ...scopes, chrome: on ? 'theme' : 'own' }).catch(error => notify(getError(error), true))}/>\n </Row>\n <AccountThemes notify={notify}/>\n <PaneThemes notify={notify}/>\n </Section>\n\n <DownloadedFonts notify={notify}/>\n {(panelSite().appearance?.extra ?? []).map((Extra, index) => <Extra key={index} notify={notify} openSection={id => window.dispatchEvent(new CustomEvent('bt-panel-section', { detail: id }))}/>)}\n <CustomCssEditor notify={notify}/>\n </>;\n}\n\n/** Theme choices for a scope row: follow (the level above) plus every theme with its swatch. */\n/** The theme doctor's full report on the theme as it is now: every finding, where it is, what it found, how to fix it. Advice only. */\nfunction DoctorReport({ theme }: { theme: ThemeSpec }) {\n const t = useT();\n const advice = themeDoctor(theme);\n const words = (item: DoctorAdvice, part: 'found' | 'fix') => t(`wb.doctor.${item.key}.${part}`, item.params);\n return <Section title={t('wb.doctor.title')} id=\"theme-doctor\" hint={t('wb.doctor.hint')} action={<Badge tone={advice.length ? undefined : 'ok'}>{t('wb.doctor.count', { count: advice.length })}</Badge>}>\n {advice.length === 0\n ? <p className=\"btp-hint\">{t('wb.doctor.empty')}</p>\n : <ul className=\"bt-doctor\" aria-label={t('wb.doctor.title')}>\n {advice.map((item, index) => <li key={`${item.id}:${item.where}:${index}`} className={`bt-doctor-item is-${item.kind}`}>\n <span className=\"bt-doctor-head\"><Badge>{t(`wb.doctor.kind.${item.kind}`)}</Badge><strong>{words(item, 'found')}</strong></span>\n <small className=\"bt-doctor-line\">{t('wb.doctor.where')}: <code>{item.where}</code></small>\n <small className=\"bt-doctor-line\">{t('wb.doctor.fix')}: {words(item, 'fix')}</small>\n </li>)}\n </ul>}\n </Section>;\n}\n\nfunction scopeOptions(follow: string): Array<Option<string>> {\n // Called during render of components that use useT(), so the labels follow the language.\n return [{ value: '', label: follow }, ...panelThemes().store.allThemes().map(theme => ({ value: theme.id, label: theme.name, icon: <ThemeDots theme={theme}/> }))];\n}\n\nfunction AccountThemes({ notify }: { notify: Notify }) {\n const t = useT();\n const { setScopes, themeName, themeState } = panelThemes().store;\n const profiles = useProfiles();\n const { scopes, choice } = useThemeState();\n return <Row label={t('wb.panel.section.accounts')} hint={t('wb.appearance.accountsHint')} keywords=\"account profile per account theme login\" wide>\n <div className=\"wb-scope-list\">\n {profiles.profiles.map(profile => <div key={profile.id} className=\"wb-scope\">\n <span className=\"wb-scope-who\"><AccountAvatar profile={profile} size={26}/><span><b>{accountName(profile)}</b><small>{scopes.profiles[profile.id] ? t('wb.appearance.ownTheme') : t('wb.appearance.followsApp', { name: themeName(choice.preset) })}</small></span></span>\n <Select label={t('wb.appearance.themeFor', { name: accountName(profile) })} value={scopes.profiles[profile.id] ?? ''} width={210} options={scopeOptions(t('wb.appearance.followApp'))}\n onChange={id => void setScopes(assign(themeState().scopes, 'profiles', profile.id, id || null)).catch(error => notify(getError(error), true))}/>\n </div>)}\n </div>\n </Row>;\n}\n\n/** Open site panes, each with the theme it shows and where that comes from. */\nfunction PaneThemes({ notify }: { notify: Notify }) {\n const t = useT();\n const { setScopes, tabTheme, themeName, themeState } = panelThemes().store;\n const { scopes } = useThemeState();\n const [, refresh] = useState(0);\n useEffect(() => {\n const api = shell.api;\n if (!api) return;\n const bump = () => refresh(n => n + 1);\n const subs = [api.onDidAddPanel(bump), api.onDidRemovePanel(bump), api.onDidLayoutChange(bump)];\n return () => subs.forEach(sub => sub.dispose());\n }, []);\n const panes = (shell.api?.panels ?? []).filter(panel => (panel.params as WebParams | undefined)?.kind === 'web');\n return <Row label={t('wb.appearance.panes')} hint={panes.length ? t('wb.appearance.panesHint') : t('wb.appearance.panesEmpty')} keywords=\"pane split tab per pane theme\" wide>\n {panes.length > 0 && <div className=\"wb-scope-list\">\n {panes.map(panel => {\n const params = panel.params as WebParams;\n const profile = tabProfile(shell.profiles, params.profile);\n const current = tabTheme({ id: panel.id, profile: profile.id });\n return <div key={panel.id} className=\"wb-scope\">\n <span className=\"wb-scope-who\"><ThemeDots theme={current.theme}/><span><b>{panel.api.title || params.url}</b><small>{accountName(profile)} · {current.source === 'pane' ? t('wb.appearance.ownTheme') : current.source === 'account' ? t('wb.appearance.accountTheme', { name: themeName(current.id) }) : t('wb.appearance.appTheme', { name: themeName(current.id) })}</small></span></span>\n <Select label={t('wb.appearance.themeFor', { name: panel.api.title || t('wb.appearance.pane') })} value={scopes.panes[panel.id] ?? ''} width={210} options={scopeOptions(t('wb.appearance.followAccount'))}\n onChange={id => void setScopes(assign(themeState().scopes, 'panes', panel.id, id || null)).catch(error => notify(getError(error), true))}/>\n </div>;\n })}\n </div>}\n </Row>;\n}\n\nfunction DownloadedFonts({ notify }: { notify: Notify }) {\n const t = useT();\n const { removeFont } = panelThemes().store;\n const { fonts } = useThemeState();\n const query = useSettingsQuery();\n const title = t('wb.appearance.downloaded');\n if (query && !`downloaded fonts google fonts typeface remove storage ${title}`.toLowerCase().includes(query.toLowerCase().trim())) return null;\n const total = fonts.reduce((sum, font) => sum + font.bytes, 0);\n return <Section title={title} id=\"fonts\" hint={fonts.length ? t('wb.appearance.downloadedHint', { count: fonts.length, size: bytesLabel(total) }) : t('wb.appearance.downloadedEmpty')}>\n <Row label={fonts.length ? t('wb.appearance.families') : t('wb.appearance.noneYet')} hint={t('wb.appearance.familiesHint')} keywords=\"google fonts downloaded remove\" wide>\n {fonts.length > 0 && <ul className=\"wb-fontlist\">\n {fonts.map(font => <li key={font.family}>\n <span><b style={{ fontFamily: `\"${font.family}\", system-ui` }}>{font.family}</b><br/><small>{weightsLabel(font.weights)} · {bytesLabel(font.bytes)}</small></span>\n <small>{formatDate(font.installedAt, { dateStyle: 'medium' })}</small>\n <Button size=\"sm\" tone=\"ghost\" onClick={() => void removeFont(font.family).then(() => notify(t('wb.appearance.removedFont', { family: font.family }))).catch(error => notify(getError(error), true))}>{t('wb.common.remove')}</Button>\n </li>)}\n </ul>}\n </Row>\n </Section>;\n}\n\n/** The selected theme's own CSS: travels with the theme (export, Save as theme); switching themes starts clean, like every customization. */\nfunction ThemeCssEditor({ css, onApply }: { css: string; onApply(text: string): void }) {\n const t = useT();\n const [text, setText] = useState(css);\n const query = useSettingsQuery();\n useEffect(() => setText(css), [css]);\n const label = t('wb.appearance.themeCss');\n if (query && !`theme css stylesheet style code custom ${label}`.toLowerCase().includes(query.toLowerCase().trim())) return null;\n const dirty = text !== css;\n return <Row label={label} hint={t('wb.appearance.themeCssHint')} keywords=\"css stylesheet style code custom\" wide>\n <div className=\"bt-code is-compact\" style={{ width: '100%' }}>\n <textarea aria-label={t('wb.appearance.themeCssLabel')} spellCheck={false} value={text} placeholder={panelSite().cssExamples?.theme ?? '/* CSS that travels with this theme */'}\n onChange={event => setText(event.target.value)}\n onKeyDown={event => { if ((event.ctrlKey || event.metaKey) && event.key === 's') { event.preventDefault(); if (dirty) onApply(text); } }}/>\n <div className=\"bt-code-bar\">\n <small>{t('wb.appearance.cssLines', { count: text.split('\\n').length })}</small>\n {dirty && <Button size=\"sm\" tone=\"ghost\" onClick={() => setText(css)}>{t('wb.common.discard')}</Button>}\n <Button size=\"sm\" tone=\"primary\" disabled={!dirty} onClick={() => onApply(text)}>{t('wb.common.apply')}</Button>\n </div>\n </div>\n </Row>;\n}\n\nfunction Glyph({ d }: { d: string }) {\n return <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d={d} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>;\n}\n\nfunction ImportPanel({ onImport, onCancel }: { onImport(theme: ThemeSpec, warnings: string[]): void; onCancel(): void }) {\n const t = useT();\n const [text, setText] = useState('');\n const [error, setError] = useState('');\n const file = useRef<HTMLInputElement>(null);\n const run = (json: string) => {\n const parsed = parseThemeJson(json);\n if ('error' in parsed) { setError(parsed.error); return; }\n // The theme doctor: advice only (never a block); contrast is already in the warnings.\n const hints = themeDoctor(parsed.theme).filter(advice => advice.kind !== 'contrast');\n onImport(parsed.theme, hints.length ? [...parsed.warnings, t('wb.appearance.doctorHints', { count: hints.length, hint: t(`wb.doctor.${hints[0]!.key}.found`, hints[0]!.params) })] : parsed.warnings);\n };\n return <div className=\"bt-import\">\n <div className=\"bt-import-drop\" onDragOver={event => event.preventDefault()}\n onDrop={event => { event.preventDefault(); void event.dataTransfer.files[0]?.text().then(run); }}>\n <strong>{t('wb.appearance.importTitle')}</strong>\n <p>{t('wb.appearance.importText')}</p>\n <div className=\"bt-inline\"><Button size=\"sm\" tone=\"primary\" onClick={() => file.current?.click()}>{t('wb.common.chooseFile')}</Button><Button size=\"sm\" tone=\"ghost\" onClick={onCancel}>{t('wb.common.cancel')}</Button></div>\n <input ref={file} type=\"file\" hidden accept=\"application/json,.json\" onChange={event => { void event.target.files?.[0]?.text().then(run); event.target.value = ''; }}/>\n </div>\n <div className=\"bt-code is-compact\">\n <textarea aria-label={t('wb.appearance.themeJson')} spellCheck={false} placeholder={`${t('wb.appearance.pasteJson')}\\n{ \"name\": \"My theme\", \"colors\": { … } }`} value={text} onChange={event => { setText(event.target.value); setError(''); }}/>\n <div className=\"bt-code-bar\">\n {error ? <small className=\"is-error\" role=\"alert\">{error}</small> : <small>{t('wb.appearance.importSafe')}</small>}\n <Button size=\"sm\" disabled={!text.trim()} onClick={() => run(text)}>{t('wb.appearance.importJson')}</Button>\n </div>\n </div>\n </div>;\n}\n\n"]}
@@ -0,0 +1,5 @@
1
+ import { type Notify } from './site.ts';
2
+ import './backup.css';
3
+ export declare function BackupPanel({ notify }: {
4
+ notify: Notify;
5
+ }): import("react").JSX.Element;