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
@@ -0,0 +1,189 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // The font browser: every Google Fonts family (offline catalog) with live previews rendered in the
3
+ // font itself, category filters and search, a detail view with editable sample text and weight
4
+ // selection, plus the built-in and system fonts. Google fonts are downloaded natively once (woff2
5
+ // from fonts.googleapis.com / fonts.gstatic.com into app data), then the site's page loads them from bytes.
6
+ import { useEffect, useMemo, useRef, useState } from 'react';
7
+ import { createPortal } from 'react-dom';
8
+ import { FONT_CHOICES, fontStack, sanitizeFonts } from "../../../runtime/themeSpec.js";
9
+ import { invoke } from "../../frame/bridge.js";
10
+ import { useT } from "../../frame/hooks.js";
11
+ import { tx } from "../../frame/i18n.js";
12
+ import { Button, Segmented, Slider } from "../controls.js";
13
+ import { panelThemes } from "../site.js";
14
+ import { themeStore, useThemeState } from "../themes.js";
15
+ import { CATEGORIES, availableWeights, bytesLabel, defaultWeights, loadCatalog, searchFonts, specimenUrl, stackFor, weightsLabel, } from "./catalog.js";
16
+ const PAGE = 60;
17
+ const SAMPLES = [
18
+ 'The quick brown fox jumps over the lazy dog',
19
+ 'Your timeline, your way. 1,284 likes · 3.2K reposts',
20
+ 'Pijamalı hasta yağız şoföre çabucak güvendi',
21
+ ];
22
+ /** Renders `text` in `font`: the installed family, else a tiny text-subset preview fetched natively. */
23
+ function FontText({ font, text, weight, className, eager }) {
24
+ const ref = useRef(null);
25
+ const [family, setFamily] = useState(null);
26
+ const [visible, setVisible] = useState(!!eager);
27
+ const { ensureShellFont, isInstalled, previewFont } = themeStore();
28
+ const installed = isInstalled(font.family);
29
+ useEffect(() => {
30
+ if (visible)
31
+ return;
32
+ const node = ref.current;
33
+ if (!node || typeof IntersectionObserver === 'undefined') {
34
+ setVisible(true);
35
+ return;
36
+ }
37
+ const observer = new IntersectionObserver(entries => { if (entries.some(entry => entry.isIntersecting)) {
38
+ setVisible(true);
39
+ observer.disconnect();
40
+ } }, { rootMargin: '120px' });
41
+ observer.observe(node);
42
+ return () => observer.disconnect();
43
+ }, [visible]);
44
+ useEffect(() => {
45
+ if (!visible || !text)
46
+ return;
47
+ let live = true;
48
+ const timer = setTimeout(() => {
49
+ const load = installed
50
+ ? ensureShellFont(font.family).then(ok => ok ? font.family : null)
51
+ : previewFont(font.family, font.axis ? { kind: 'range', min: font.axis[0], max: font.axis[1] } : { kind: 'list', values: font.weights.slice(0, 9) }, [...new Set(text)].join('').slice(0, 120));
52
+ void load.then(name => { if (live)
53
+ setFamily(name); });
54
+ }, eager ? 250 : 0);
55
+ return () => { live = false; clearTimeout(timer); };
56
+ }, [visible, text, font.family, installed]);
57
+ return _jsx("span", { ref: ref, className: `${className ?? ''} ${family ? 'is-ready' : 'is-loading'}`, style: { fontFamily: family ? `"${family}", ${stackFor(font).slice(1).join(', ')}` : undefined, fontWeight: weight }, children: text });
58
+ }
59
+ export function FontBrowser({ role, current, onPick, onClose }) {
60
+ const t = useT();
61
+ const { fonts: installedFonts } = useThemeState();
62
+ const [tab, setTab] = useState('google');
63
+ const [catalog, setCatalog] = useState([]);
64
+ const [query, setQuery] = useState('');
65
+ const [category, setCategory] = useState('all');
66
+ const [onlyInstalled, setOnlyInstalled] = useState(false);
67
+ const [limit, setLimit] = useState(PAGE);
68
+ const [selected, setSelected] = useState(current);
69
+ const [active, setActive] = useState(0);
70
+ const search = useRef(null);
71
+ const list = useRef(null);
72
+ const root = useRef(null);
73
+ useEffect(() => { void loadCatalog().then(setCatalog); search.current?.focus(); }, []);
74
+ useEffect(() => {
75
+ const onKey = (event) => { if (event.key === 'Escape') {
76
+ event.preventDefault();
77
+ event.stopPropagation();
78
+ onClose();
79
+ } };
80
+ window.addEventListener('keydown', onKey, true);
81
+ return () => window.removeEventListener('keydown', onKey, true);
82
+ }, [onClose]);
83
+ const installed = useMemo(() => new Set(installedFonts.map(font => font.family)), [installedFonts]);
84
+ const results = useMemo(() => searchFonts(catalog, { query, category, only: onlyInstalled ? installed : undefined }), [catalog, query, category, onlyInstalled, installed]);
85
+ useEffect(() => { setLimit(PAGE); setActive(0); list.current?.scrollTo({ top: 0 }); }, [query, category, onlyInstalled]);
86
+ const shown = results.slice(0, limit);
87
+ const detail = catalog.find(font => font.family === selected) ?? shown[0] ?? null;
88
+ const onListKey = (event) => {
89
+ if (!shown.length)
90
+ return;
91
+ const move = (index) => {
92
+ const next = Math.max(0, Math.min(shown.length - 1, index));
93
+ setActive(next);
94
+ list.current?.querySelectorAll('li')[next]?.scrollIntoView({ block: 'nearest' });
95
+ };
96
+ if (event.key === 'ArrowDown') {
97
+ event.preventDefault();
98
+ move(active + 1);
99
+ }
100
+ else if (event.key === 'ArrowUp') {
101
+ event.preventDefault();
102
+ if (active === 0 && event.target === list.current)
103
+ search.current?.focus();
104
+ else
105
+ move(active - 1);
106
+ }
107
+ else if (event.key === 'PageDown') {
108
+ event.preventDefault();
109
+ move(active + 8);
110
+ }
111
+ else if (event.key === 'PageUp') {
112
+ event.preventDefault();
113
+ move(active - 8);
114
+ }
115
+ else if (event.key === 'Enter' || event.key === ' ') {
116
+ event.preventDefault();
117
+ setSelected(shown[active].family);
118
+ }
119
+ };
120
+ // Inside the panel (not the whole window): site panes are native webviews above the shell elsewhere.
121
+ return createPortal(_jsx("div", { className: "wb-sheet-backdrop", onMouseDown: event => { if (event.target === event.currentTarget)
122
+ onClose(); }, children: _jsxs("div", { ref: root, className: "wb-sheet wb-fb", role: "dialog", "aria-modal": "true", "aria-label": t('wb.fonts.chooseFor', { role }), children: [_jsxs("header", { className: "wb-sheet-head", children: [_jsxs("div", { children: [_jsxs("h2", { children: [t('wb.fonts.choose'), " ", _jsx("span", { children: t('wb.fonts.forRole', { role }) })] }), _jsx("p", { children: tab === 'google' ? t('wb.fonts.googleCount', { count: catalog.length || 1800 }) : t('wb.fonts.systemHint') })] }), _jsx(Segmented, { label: t('wb.fonts.source'), size: "sm", value: tab, onChange: setTab, options: [{ value: 'google', label: 'Google Fonts' }, { value: 'system', label: t('wb.fonts.builtIn') }] }), _jsx("button", { type: "button", className: "wb-sheet-close", "aria-label": t('wb.common.close'), onClick: onClose, children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: _jsx("path", { d: "m3.5 3.5 7 7m0-7-7 7", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }) }) })] }), tab === 'system' ? _jsx(SystemFonts, { current: current, onPick: onPick }) : _jsxs(_Fragment, { children: [_jsxs("div", { className: "wb-fb-tools", children: [_jsxs("label", { className: "bt-search wb-fb-search", children: [_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 16 16", "aria-hidden": "true", children: [_jsx("circle", { cx: "7", cy: "7", r: "4.75", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }), _jsx("path", { d: "m10.5 10.5 3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] }), _jsx("input", { ref: search, type: "search", "aria-label": t('wb.fonts.search'), placeholder: t('wb.fonts.searchPlaceholder'), value: query, onChange: event => setQuery(event.target.value), onKeyDown: event => {
123
+ if (event.key === 'ArrowDown') {
124
+ event.preventDefault();
125
+ list.current?.focus();
126
+ setActive(0);
127
+ }
128
+ if (event.key === 'Enter' && shown[0]) {
129
+ event.preventDefault();
130
+ setSelected(shown[0].family);
131
+ }
132
+ } })] }), _jsxs("div", { className: "wb-fb-cats", role: "radiogroup", "aria-label": t('wb.fonts.category'), children: [CATEGORIES.map(item => _jsx("button", { type: "button", role: "radio", "aria-checked": category === item, className: category === item ? 'is-on' : '', onClick: () => setCategory(item), children: tx(`wb.fonts.category.${item}`) }, item)), _jsxs("button", { type: "button", role: "checkbox", "aria-checked": onlyInstalled, className: `wb-fb-installed ${onlyInstalled ? 'is-on' : ''}`, onClick: () => setOnlyInstalled(!onlyInstalled), children: [t('wb.fonts.downloaded'), installed.size ? ` · ${installed.size}` : ''] })] })] }), _jsxs("div", { className: "wb-fb-body", children: [_jsxs("ul", { ref: list, className: "wb-fb-list", role: "listbox", tabIndex: 0, "aria-label": t('wb.fonts.families'), "aria-activedescendant": shown[active] ? `wb-fb-${active}` : undefined, onKeyDown: onListKey, children: [!catalog.length && _jsx("li", { className: "wb-fb-empty", children: t('wb.fonts.loadingCatalog') }), catalog.length > 0 && !shown.length && _jsx("li", { className: "wb-fb-empty", children: t('wb.fonts.noMatch', { query }) }), shown.map((font, index) => _jsxs("li", { id: `wb-fb-${index}`, role: "option", "aria-selected": font.family === selected, className: `${index === active ? 'is-active' : ''} ${font.family === selected ? 'is-on' : ''}`, onPointerEnter: () => setActive(index), onClick: () => { setActive(index); setSelected(font.family); }, children: [_jsx(FontText, { font: font, text: font.family, className: "wb-fb-name" }), _jsxs("span", { className: "wb-fb-meta", children: [tx(`wb.fonts.categoryName.${font.category}`), " \u00B7 ", font.axis ? t('wb.fonts.variable') : t('wb.fonts.weightCount', { count: font.weights.length })] }), installed.has(font.family) && _jsx("span", { className: "wb-fb-tag", children: t('wb.fonts.downloaded') }), current === font.family && _jsx("span", { className: "wb-fb-tag is-accent", children: t('wb.fonts.inUse') })] }, font.family)), results.length > limit && _jsx("li", { className: "wb-fb-more", children: _jsx(Button, { size: "sm", tone: "ghost", onClick: () => setLimit(limit + PAGE), children: t('wb.fonts.showMore', { count: Math.min(PAGE, results.length - limit), total: results.length }) }) })] }), _jsx(FontDetail, { font: detail, role: role, onPick: onPick }, detail?.family ?? 'none')] })] }), _jsx("footer", { className: "wb-sheet-foot", children: t('wb.fonts.footer') })] }) }), document.querySelector('.btp') ?? document.body);
133
+ }
134
+ function FontDetail({ font, role, onPick }) {
135
+ const t = useT();
136
+ const { installFont } = themeStore();
137
+ const { fonts } = useThemeState();
138
+ const [sample, setSample] = useState(SAMPLES[0]);
139
+ const [weight, setWeight] = useState(400);
140
+ const [weights, setWeights] = useState(font ? defaultWeights(font) : null);
141
+ const [busy, setBusy] = useState(false);
142
+ const [error, setError] = useState('');
143
+ useEffect(() => {
144
+ if (!font)
145
+ return;
146
+ const available = availableWeights(font);
147
+ setWeight(available.includes(400) ? 400 : available[0] ?? 400);
148
+ }, [font?.family]);
149
+ if (!font || !weights)
150
+ return _jsx("div", { className: "wb-fb-detail is-empty", children: _jsx("p", { children: t('wb.fonts.detailEmpty', { role }) }) });
151
+ const installed = fonts.find(item => item.family === font.family);
152
+ const available = availableWeights(font);
153
+ const pick = async () => {
154
+ setError('');
155
+ if (!installed || JSON.stringify(installed.weights) !== JSON.stringify(weights)) {
156
+ setBusy(true);
157
+ try {
158
+ await installFont(font.family, weights);
159
+ }
160
+ catch (reason) {
161
+ setBusy(false);
162
+ setError(reason instanceof Error ? reason.message : String(reason));
163
+ return;
164
+ }
165
+ setBusy(false);
166
+ }
167
+ onPick({ family: stackFor(font), source: 'google' });
168
+ };
169
+ const toggle = (value) => {
170
+ if (weights.kind !== 'list')
171
+ return;
172
+ const values = weights.values.includes(value) ? weights.values.filter(item => item !== value) : [...weights.values, value].sort((a, b) => a - b);
173
+ if (values.length)
174
+ setWeights({ kind: 'list', values });
175
+ };
176
+ return _jsxs("div", { className: "wb-fb-detail", children: [_jsxs("div", { className: "wb-fb-hero", children: [_jsx(FontText, { font: font, text: font.family, className: "wb-fb-hero-name", weight: weight, eager: true }), _jsxs("span", { className: "wb-fb-hero-meta", children: [tx(`wb.fonts.categoryName.${font.category}`), " \u00B7 ", font.axis ? t('wb.fonts.variableRange', { min: font.axis[0], max: font.axis[1] }) : t('wb.fonts.weightsList', { weights: font.weights.join(', ') }), installed ? ` · ${t('wb.fonts.downloadedSize', { size: bytesLabel(installed.bytes) })}` : ''] })] }), _jsxs("div", { className: "wb-fb-sample", children: [_jsx(FontText, { font: font, text: sample || font.family, className: "wb-fb-sample-text", weight: weight, eager: true }), _jsx("textarea", { "aria-label": t('wb.fonts.sample'), value: sample, maxLength: 120, rows: 2, spellCheck: false, onChange: event => setSample(event.target.value) }), _jsx("div", { className: "wb-fb-samples", children: SAMPLES.map(text => _jsxs("button", { type: "button", className: text === sample ? 'is-on' : '', onClick: () => setSample(text), children: [text.slice(0, 18), "\u2026"] }, text)) })] }), _jsxs("div", { className: "wb-fb-field", children: [_jsx("span", { children: t('wb.fonts.previewWeight') }), font.axis
177
+ ? _jsx(Slider, { label: t('wb.fonts.previewWeight'), min: font.axis[0], max: font.axis[1], step: 10, value: weight, format: v => String(v), onChange: setWeight })
178
+ : _jsx("div", { className: "wb-fb-weights", role: "radiogroup", "aria-label": t('wb.fonts.previewWeight'), children: available.map(value => _jsx("button", { type: "button", role: "radio", "aria-checked": weight === value, className: weight === value ? 'is-on' : '', onClick: () => setWeight(value), children: value }, value)) })] }), _jsxs("div", { className: "wb-fb-field", children: [_jsx("span", { children: t('wb.panel.updates.download') }), weights.kind === 'range'
179
+ ? _jsxs("div", { className: "wb-fb-range", children: [_jsx(Slider, { label: t('wb.fonts.lightest'), min: font.axis[0], max: weights.max, step: 100, value: weights.min, format: v => t('wb.fonts.fromWeight', { weight: v }), onChange: min => setWeights({ ...weights, min }) }), _jsx(Slider, { label: t('wb.fonts.heaviest'), min: weights.min, max: font.axis[1], step: 100, value: weights.max, format: v => t('wb.fonts.toWeight', { weight: v }), onChange: max => setWeights({ ...weights, max }) })] })
180
+ : _jsx("div", { className: "wb-fb-weights", role: "group", "aria-label": t('wb.fonts.weightsToDownload'), children: available.map(value => _jsx("button", { type: "button", role: "checkbox", "aria-checked": weights.values.includes(value), className: weights.values.includes(value) ? 'is-on' : '', onClick: () => toggle(value), children: value }, value)) }), _jsxs("small", { children: [font.axis ? t('wb.fonts.variableFile') : t('wb.fonts.staticFiles'), " ", weightsLabel(weights)] })] }), error && _jsx("p", { className: "wb-fb-error", role: "alert", children: error }), _jsxs("div", { className: "wb-fb-actions", children: [_jsx(Button, { tone: "primary", disabled: busy, onClick: () => void pick(), children: busy ? t('wb.fonts.downloading') : installed && JSON.stringify(installed.weights) === JSON.stringify(weights) ? t('wb.fonts.useFor', { role }) : t('wb.fonts.downloadUseFor', { role }) }), _jsx(Button, { tone: "ghost", onClick: () => void invoke('open_external_url', { url: specimenUrl(font.family) }).catch(() => { }), children: t('wb.fonts.license') })] })] });
181
+ }
182
+ function SystemFonts({ current, onPick }) {
183
+ const t = useT();
184
+ const [custom, setCustom] = useState('');
185
+ const valid = sanitizeFonts([custom.trim()]).length === 1;
186
+ return _jsxs("div", { className: "wb-fb-system", children: [_jsx("ul", { className: "wb-fb-grid", children: (panelThemes().fontChoices ?? FONT_CHOICES).filter(choice => choice.family.length).map(choice => _jsx("li", { children: _jsxs("button", { type: "button", className: current === choice.family[0] ? 'is-on' : '', onClick: () => onPick({ family: choice.family }), children: [_jsx("span", { style: { fontFamily: fontStack(choice.family) }, children: choice.key ? tx(choice.key, undefined, choice.label) : choice.label }), _jsx("small", { style: { fontFamily: fontStack(choice.family) }, children: "Aa Bb 0123 \u00B7 The quick brown fox" })] }) }, choice.id)) }), _jsxs("form", { className: "wb-fb-custom", onSubmit: event => { event.preventDefault(); if (valid)
187
+ onPick({ family: [custom.trim(), 'system-ui', 'sans-serif'] }); }, children: [_jsxs("label", { children: [_jsx("span", { children: t('wb.fonts.installedFont') }), _jsx("input", { value: custom, placeholder: t('wb.fonts.installedPlaceholder'), onChange: event => setCustom(event.target.value), style: valid ? { fontFamily: fontStack([custom.trim()]) } : undefined })] }), _jsx(Button, { type: "submit", size: "sm", disabled: !valid, children: t('wb.fonts.useIt') })] })] });
188
+ }
189
+ //# sourceMappingURL=FontBrowser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontBrowser.js","sourceRoot":"","sources":["../../../../../../../shell/src/panel/fonts/FontBrowser.tsx"],"names":[],"mappings":"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","sourcesContent":["// The font browser: every Google Fonts family (offline catalog) with live previews rendered in the\n// font itself, category filters and search, a detail view with editable sample text and weight\n// selection, plus the built-in and system fonts. Google fonts are downloaded natively once (woff2\n// from fonts.googleapis.com / fonts.gstatic.com into app data), then the site's page loads them from bytes.\nimport { useEffect, useMemo, useRef, useState, type KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport { createPortal } from 'react-dom';\nimport { FONT_CHOICES, fontStack, sanitizeFonts } from '../../../../runtime/src/themeSpec.ts';\nimport { invoke } from '../../frame/bridge.ts';\nimport { useT } from '../../frame/hooks.ts';\nimport { tx } from '../../frame/i18n.ts';\nimport { Button, Segmented, Slider } from '../controls.tsx';\nimport { panelThemes } from '../site.ts';\nimport { themeStore, useThemeState } from '../themes.ts';\nimport {\n CATEGORIES, availableWeights, bytesLabel, defaultWeights, loadCatalog, searchFonts, specimenUrl, stackFor, weightsLabel,\n type CatalogFont, type Category, type Weights,\n} from './catalog.ts';\n\nexport type FontPick = { family: string[]; source?: 'google' };\nconst PAGE = 60;\nconst SAMPLES = [\n 'The quick brown fox jumps over the lazy dog',\n 'Your timeline, your way. 1,284 likes · 3.2K reposts',\n 'Pijamalı hasta yağız şoföre çabucak güvendi',\n];\n\n/** Renders `text` in `font`: the installed family, else a tiny text-subset preview fetched natively. */\nfunction FontText({ font, text, weight, className, eager }: { font: CatalogFont; text: string; weight?: number; className?: string; eager?: boolean }) {\n const ref = useRef<HTMLSpanElement>(null);\n const [family, setFamily] = useState<string | null>(null);\n const [visible, setVisible] = useState(!!eager);\n const { ensureShellFont, isInstalled, previewFont } = themeStore();\n const installed = isInstalled(font.family);\n useEffect(() => {\n if (visible) return;\n const node = ref.current;\n if (!node || typeof IntersectionObserver === 'undefined') { setVisible(true); return; }\n const observer = new IntersectionObserver(entries => { if (entries.some(entry => entry.isIntersecting)) { setVisible(true); observer.disconnect(); } }, { rootMargin: '120px' });\n observer.observe(node);\n return () => observer.disconnect();\n }, [visible]);\n useEffect(() => {\n if (!visible || !text) return;\n let live = true;\n const timer = setTimeout(() => {\n const load = installed\n ? ensureShellFont(font.family).then(ok => ok ? font.family : null)\n : previewFont(font.family, font.axis ? { kind: 'range', min: font.axis[0], max: font.axis[1] } : { kind: 'list', values: font.weights.slice(0, 9) }, [...new Set(text)].join('').slice(0, 120));\n void load.then(name => { if (live) setFamily(name); });\n }, eager ? 250 : 0);\n return () => { live = false; clearTimeout(timer); };\n }, [visible, text, font.family, installed]);\n return <span ref={ref} className={`${className ?? ''} ${family ? 'is-ready' : 'is-loading'}`}\n style={{ fontFamily: family ? `\"${family}\", ${stackFor(font).slice(1).join(', ')}` : undefined, fontWeight: weight }}>{text}</span>;\n}\n\nexport function FontBrowser({ role, current, onPick, onClose }: { role: string; current: string | null; onPick(pick: FontPick): void; onClose(): void }) {\n const t = useT();\n const { fonts: installedFonts } = useThemeState();\n const [tab, setTab] = useState<'google' | 'system'>('google');\n const [catalog, setCatalog] = useState<CatalogFont[]>([]);\n const [query, setQuery] = useState('');\n const [category, setCategory] = useState<Category | 'all'>('all');\n const [onlyInstalled, setOnlyInstalled] = useState(false);\n const [limit, setLimit] = useState(PAGE);\n const [selected, setSelected] = useState<string | null>(current);\n const [active, setActive] = useState(0);\n const search = useRef<HTMLInputElement>(null);\n const list = useRef<HTMLUListElement>(null);\n const root = useRef<HTMLDivElement>(null);\n\n useEffect(() => { void loadCatalog().then(setCatalog); search.current?.focus(); }, []);\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); onClose(); } };\n window.addEventListener('keydown', onKey, true);\n return () => window.removeEventListener('keydown', onKey, true);\n }, [onClose]);\n\n const installed = useMemo(() => new Set(installedFonts.map(font => font.family)), [installedFonts]);\n const results = useMemo(() => searchFonts(catalog, { query, category, only: onlyInstalled ? installed : undefined }), [catalog, query, category, onlyInstalled, installed]);\n useEffect(() => { setLimit(PAGE); setActive(0); list.current?.scrollTo({ top: 0 }); }, [query, category, onlyInstalled]);\n const shown = results.slice(0, limit);\n const detail = catalog.find(font => font.family === selected) ?? shown[0] ?? null;\n\n const onListKey = (event: ReactKeyboardEvent) => {\n if (!shown.length) return;\n const move = (index: number) => {\n const next = Math.max(0, Math.min(shown.length - 1, index));\n setActive(next);\n list.current?.querySelectorAll('li')[next]?.scrollIntoView({ block: 'nearest' });\n };\n if (event.key === 'ArrowDown') { event.preventDefault(); move(active + 1); }\n else if (event.key === 'ArrowUp') { event.preventDefault(); if (active === 0 && event.target === list.current) search.current?.focus(); else move(active - 1); }\n else if (event.key === 'PageDown') { event.preventDefault(); move(active + 8); }\n else if (event.key === 'PageUp') { event.preventDefault(); move(active - 8); }\n else if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); setSelected(shown[active]!.family); }\n };\n\n // Inside the panel (not the whole window): site panes are native webviews above the shell elsewhere.\n return createPortal(<div className=\"wb-sheet-backdrop\" onMouseDown={event => { if (event.target === event.currentTarget) onClose(); }}>\n <div ref={root} className=\"wb-sheet wb-fb\" role=\"dialog\" aria-modal=\"true\" aria-label={t('wb.fonts.chooseFor', { role })}>\n <header className=\"wb-sheet-head\">\n <div>\n <h2>{t('wb.fonts.choose')} <span>{t('wb.fonts.forRole', { role })}</span></h2>\n <p>{tab === 'google' ? t('wb.fonts.googleCount', { count: catalog.length || 1800 }) : t('wb.fonts.systemHint')}</p>\n </div>\n <Segmented<'google' | 'system'> label={t('wb.fonts.source')} size=\"sm\" value={tab} onChange={setTab} options={[{ value: 'google', label: 'Google Fonts' }, { value: 'system', label: t('wb.fonts.builtIn') }]}/>\n <button type=\"button\" className=\"wb-sheet-close\" aria-label={t('wb.common.close')} onClick={onClose}><svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\"><path d=\"m3.5 3.5 7 7m0-7-7 7\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\"/></svg></button>\n </header>\n {tab === 'system' ? <SystemFonts current={current} onPick={onPick}/> : <>\n <div className=\"wb-fb-tools\">\n <label className=\"bt-search wb-fb-search\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><circle cx=\"7\" cy=\"7\" r=\"4.75\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\"/><path d=\"m10.5 10.5 3 3\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/></svg>\n <input ref={search} type=\"search\" aria-label={t('wb.fonts.search')} placeholder={t('wb.fonts.searchPlaceholder')} value={query}\n onChange={event => setQuery(event.target.value)}\n onKeyDown={event => {\n if (event.key === 'ArrowDown') { event.preventDefault(); list.current?.focus(); setActive(0); }\n if (event.key === 'Enter' && shown[0]) { event.preventDefault(); setSelected(shown[0].family); }\n }}/>\n </label>\n <div className=\"wb-fb-cats\" role=\"radiogroup\" aria-label={t('wb.fonts.category')}>\n {CATEGORIES.map(item => <button key={item} type=\"button\" role=\"radio\" aria-checked={category === item} className={category === item ? 'is-on' : ''} onClick={() => setCategory(item)}>{tx(`wb.fonts.category.${item}`)}</button>)}\n <button type=\"button\" role=\"checkbox\" aria-checked={onlyInstalled} className={`wb-fb-installed ${onlyInstalled ? 'is-on' : ''}`} onClick={() => setOnlyInstalled(!onlyInstalled)}>\n {t('wb.fonts.downloaded')}{installed.size ? ` · ${installed.size}` : ''}</button>\n </div>\n </div>\n <div className=\"wb-fb-body\">\n <ul ref={list} className=\"wb-fb-list\" role=\"listbox\" tabIndex={0} aria-label={t('wb.fonts.families')} aria-activedescendant={shown[active] ? `wb-fb-${active}` : undefined} onKeyDown={onListKey}>\n {!catalog.length && <li className=\"wb-fb-empty\">{t('wb.fonts.loadingCatalog')}</li>}\n {catalog.length > 0 && !shown.length && <li className=\"wb-fb-empty\">{t('wb.fonts.noMatch', { query })}</li>}\n {shown.map((font, index) => <li key={font.family} id={`wb-fb-${index}`} role=\"option\" aria-selected={font.family === selected}\n className={`${index === active ? 'is-active' : ''} ${font.family === selected ? 'is-on' : ''}`}\n onPointerEnter={() => setActive(index)} onClick={() => { setActive(index); setSelected(font.family); }}>\n <FontText font={font} text={font.family} className=\"wb-fb-name\"/>\n <span className=\"wb-fb-meta\">{tx(`wb.fonts.categoryName.${font.category}`)} · {font.axis ? t('wb.fonts.variable') : t('wb.fonts.weightCount', { count: font.weights.length })}</span>\n {installed.has(font.family) && <span className=\"wb-fb-tag\">{t('wb.fonts.downloaded')}</span>}\n {current === font.family && <span className=\"wb-fb-tag is-accent\">{t('wb.fonts.inUse')}</span>}\n </li>)}\n {results.length > limit && <li className=\"wb-fb-more\"><Button size=\"sm\" tone=\"ghost\" onClick={() => setLimit(limit + PAGE)}>{t('wb.fonts.showMore', { count: Math.min(PAGE, results.length - limit), total: results.length })}</Button></li>}\n </ul>\n <FontDetail key={detail?.family ?? 'none'} font={detail} role={role} onPick={onPick}/>\n </div>\n </>}\n <footer className=\"wb-sheet-foot\">\n {t('wb.fonts.footer')}\n </footer>\n </div>\n </div>, document.querySelector('.btp') ?? document.body);\n}\n\nfunction FontDetail({ font, role, onPick }: { font: CatalogFont | null; role: string; onPick(pick: FontPick): void }) {\n const t = useT();\n const { installFont } = themeStore();\n const { fonts } = useThemeState();\n const [sample, setSample] = useState(SAMPLES[0]!);\n const [weight, setWeight] = useState(400);\n const [weights, setWeights] = useState<Weights | null>(font ? defaultWeights(font) : null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState('');\n useEffect(() => {\n if (!font) return;\n const available = availableWeights(font);\n setWeight(available.includes(400) ? 400 : available[0] ?? 400);\n }, [font?.family]);\n if (!font || !weights) return <div className=\"wb-fb-detail is-empty\"><p>{t('wb.fonts.detailEmpty', { role })}</p></div>;\n const installed = fonts.find(item => item.family === font.family);\n const available = availableWeights(font);\n const pick = async () => {\n setError('');\n if (!installed || JSON.stringify(installed.weights) !== JSON.stringify(weights)) {\n setBusy(true);\n try { await installFont(font.family, weights); }\n catch (reason) { setBusy(false); setError(reason instanceof Error ? reason.message : String(reason)); return; }\n setBusy(false);\n }\n onPick({ family: stackFor(font), source: 'google' });\n };\n const toggle = (value: number) => {\n if (weights.kind !== 'list') return;\n const values = weights.values.includes(value) ? weights.values.filter(item => item !== value) : [...weights.values, value].sort((a, b) => a - b);\n if (values.length) setWeights({ kind: 'list', values });\n };\n return <div className=\"wb-fb-detail\">\n <div className=\"wb-fb-hero\">\n <FontText font={font} text={font.family} className=\"wb-fb-hero-name\" weight={weight} eager/>\n <span className=\"wb-fb-hero-meta\">{tx(`wb.fonts.categoryName.${font.category}`)} · {font.axis ? t('wb.fonts.variableRange', { min: font.axis[0], max: font.axis[1] }) : t('wb.fonts.weightsList', { weights: font.weights.join(', ') })}{installed ? ` · ${t('wb.fonts.downloadedSize', { size: bytesLabel(installed.bytes) })}` : ''}</span>\n </div>\n <div className=\"wb-fb-sample\">\n <FontText font={font} text={sample || font.family} className=\"wb-fb-sample-text\" weight={weight} eager/>\n <textarea aria-label={t('wb.fonts.sample')} value={sample} maxLength={120} rows={2} spellCheck={false} onChange={event => setSample(event.target.value)}/>\n <div className=\"wb-fb-samples\">{SAMPLES.map(text => <button key={text} type=\"button\" className={text === sample ? 'is-on' : ''} onClick={() => setSample(text)}>{text.slice(0, 18)}…</button>)}</div>\n </div>\n <div className=\"wb-fb-field\">\n <span>{t('wb.fonts.previewWeight')}</span>\n {font.axis\n ? <Slider label={t('wb.fonts.previewWeight')} min={font.axis[0]} max={font.axis[1]} step={10} value={weight} format={v => String(v)} onChange={setWeight}/>\n : <div className=\"wb-fb-weights\" role=\"radiogroup\" aria-label={t('wb.fonts.previewWeight')}>{available.map(value => <button key={value} type=\"button\" role=\"radio\" aria-checked={weight === value} className={weight === value ? 'is-on' : ''} onClick={() => setWeight(value)}>{value}</button>)}</div>}\n </div>\n <div className=\"wb-fb-field\">\n <span>{t('wb.panel.updates.download')}</span>\n {weights.kind === 'range'\n ? <div className=\"wb-fb-range\">\n <Slider label={t('wb.fonts.lightest')} min={font.axis![0]} max={weights.max} step={100} value={weights.min} format={v => t('wb.fonts.fromWeight', { weight: v })} onChange={min => setWeights({ ...weights, min })}/>\n <Slider label={t('wb.fonts.heaviest')} min={weights.min} max={font.axis![1]} step={100} value={weights.max} format={v => t('wb.fonts.toWeight', { weight: v })} onChange={max => setWeights({ ...weights, max })}/>\n </div>\n : <div className=\"wb-fb-weights\" role=\"group\" aria-label={t('wb.fonts.weightsToDownload')}>{available.map(value => <button key={value} type=\"button\" role=\"checkbox\" aria-checked={weights.values.includes(value)} className={weights.values.includes(value) ? 'is-on' : ''} onClick={() => toggle(value)}>{value}</button>)}</div>}\n <small>{font.axis ? t('wb.fonts.variableFile') : t('wb.fonts.staticFiles')} {weightsLabel(weights)}</small>\n </div>\n {error && <p className=\"wb-fb-error\" role=\"alert\">{error}</p>}\n <div className=\"wb-fb-actions\">\n <Button tone=\"primary\" disabled={busy} onClick={() => void pick()}>{busy ? t('wb.fonts.downloading') : installed && JSON.stringify(installed.weights) === JSON.stringify(weights) ? t('wb.fonts.useFor', { role }) : t('wb.fonts.downloadUseFor', { role })}</Button>\n <Button tone=\"ghost\" onClick={() => void invoke('open_external_url', { url: specimenUrl(font.family) }).catch(() => {})}>{t('wb.fonts.license')}</Button>\n </div>\n </div>;\n}\n\nfunction SystemFonts({ current, onPick }: { current: string | null; onPick(pick: FontPick): void }) {\n const t = useT();\n const [custom, setCustom] = useState('');\n const valid = sanitizeFonts([custom.trim()]).length === 1;\n return <div className=\"wb-fb-system\">\n <ul className=\"wb-fb-grid\">\n {(panelThemes().fontChoices ?? FONT_CHOICES).filter(choice => choice.family.length).map(choice => <li key={choice.id}>\n <button type=\"button\" className={current === choice.family[0] ? 'is-on' : ''} onClick={() => onPick({ family: choice.family })}>\n <span style={{ fontFamily: fontStack(choice.family) }}>{choice.key ? tx(choice.key, undefined, choice.label) : choice.label}</span>\n <small style={{ fontFamily: fontStack(choice.family) }}>Aa Bb 0123 · The quick brown fox</small>\n </button>\n </li>)}\n </ul>\n <form className=\"wb-fb-custom\" onSubmit={event => { event.preventDefault(); if (valid) onPick({ family: [custom.trim(), 'system-ui', 'sans-serif'] }); }}>\n <label><span>{t('wb.fonts.installedFont')}</span>\n <input value={custom} placeholder={t('wb.fonts.installedPlaceholder')} onChange={event => setCustom(event.target.value)} style={valid ? { fontFamily: fontStack([custom.trim()]) } : undefined}/></label>\n <Button type=\"submit\" size=\"sm\" disabled={!valid}>{t('wb.fonts.useIt')}</Button>\n </form>\n </div>;\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { type FontRole, type FontRoleName, type FontSpec } from '../../../runtime/themeSpec.ts';
2
+ import '../builder.css';
3
+ /** A font role's name and hint in the active language (`fonts.role.<role>.label/.hint`). */
4
+ export declare const roleInfo: (role: FontRoleName) => {
5
+ label: string;
6
+ hint: string;
7
+ };
8
+ /** The name a role shows: its own first family, or where it inherits from. */
9
+ export declare function roleLabel(font: FontSpec, role: FontRoleName): {
10
+ name: string;
11
+ inherited: boolean;
12
+ stack?: string;
13
+ };
14
+ /** Loads the Google fonts a font spec names into the panel so its labels render in them. */
15
+ export declare function useShellFonts(font: FontSpec): void;
16
+ export declare function FontRoles({ font, onRole, compact }: {
17
+ font: FontSpec;
18
+ onRole(role: FontRoleName, next: FontRole, commit?: boolean): void;
19
+ compact?: boolean;
20
+ }): import("react").JSX.Element;
@@ -0,0 +1,77 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // "Which font goes where": one row per font role. Every role inherits the interface font until it
3
+ // is given its own (from Google Fonts, the bundled Geist fonts or an installed system font), and
4
+ // every role but the interface can fine-tune weight, size, letter spacing and tabular figures.
5
+ import { useEffect, useState } from 'react';
6
+ import { FONT_ROLE_NAMES, ROLE_LIMITS, fontStack, sanitizeFonts } from "../../../runtime/themeSpec.js";
7
+ import { useT } from "../../frame/hooks.js";
8
+ import { formatNumber, t, tx } from "../../frame/i18n.js";
9
+ import { Button, Select, Slider, Toggle } from "../controls.js";
10
+ import { panelSite, panelThemes } from "../site.js";
11
+ import { themeStore, useThemeState } from "../themes.js";
12
+ import { FontBrowser } from "./FontBrowser.js";
13
+ import '../builder.css';
14
+ /** A font role's name and hint in the active language (`fonts.role.<role>.label/.hint`). */
15
+ export const roleInfo = (role) => ({ label: tx(`wb.fonts.role.${role}.label`), hint: tx(`wb.fonts.role.${role}.hint`) });
16
+ const WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900];
17
+ const spec = (role) => role === 'inherit' ? { family: [] } : role;
18
+ const tidy = (next) => Object.keys(next).length === 1 && !next.family.length ? 'inherit' : next;
19
+ /** The name a role shows: its own first family, or where it inherits from. */
20
+ export function roleLabel(font, role) {
21
+ const own = font.roles[role];
22
+ if (own !== 'inherit' && own.family.length)
23
+ return { name: own.family[0], inherited: false, stack: fontStack(own.family) };
24
+ const siteFont = panelThemes().siteFont;
25
+ if (role === 'interface')
26
+ return { name: siteFont, inherited: true };
27
+ if (role === 'mono')
28
+ return { name: t('wb.fonts.monospace'), inherited: true, stack: fontStack(['Cascadia Mono', 'Consolas', 'ui-monospace', 'monospace']) };
29
+ const base = font.roles.interface;
30
+ if (base !== 'inherit' && base.family.length)
31
+ return { name: base.family[0], inherited: true, stack: fontStack(base.family) };
32
+ return { name: role === 'chrome' ? `Geist (${panelSite().brand.name})` : siteFont, inherited: true };
33
+ }
34
+ /** Loads the Google fonts a font spec names into the panel so its labels render in them. */
35
+ export function useShellFonts(font) {
36
+ const { fonts } = useThemeState();
37
+ const { ensureShellFont, isInstalled } = themeStore();
38
+ useEffect(() => {
39
+ for (const role of FONT_ROLE_NAMES) {
40
+ const value = font.roles[role];
41
+ if (value !== 'inherit' && value.source === 'google' && value.family[0] && isInstalled(value.family[0]))
42
+ void ensureShellFont(value.family[0]);
43
+ }
44
+ }, [font, fonts]);
45
+ }
46
+ export function FontRoles({ font, onRole, compact }) {
47
+ const t = useT();
48
+ const [browsing, setBrowsing] = useState(null);
49
+ const [open, setOpen] = useState(null);
50
+ useShellFonts(font);
51
+ const pick = (role, choice) => {
52
+ const current = spec(font.roles[role]);
53
+ const next = { ...current, family: sanitizeFonts(choice.family) };
54
+ if (choice.source)
55
+ next.source = choice.source;
56
+ else
57
+ delete next.source;
58
+ onRole(role, tidy(next));
59
+ setBrowsing(null);
60
+ };
61
+ return _jsxs("div", { className: `wb-roles ${compact ? 'is-compact' : ''}`, children: [FONT_ROLE_NAMES.map(role => {
62
+ const label = roleLabel(font, role);
63
+ const value = font.roles[role];
64
+ const own = spec(value);
65
+ const tuned = role !== 'interface' && (own.weight !== undefined || own.size !== undefined || own.tracking !== undefined || !!own.tabular);
66
+ const set = (patch, commit = true) => {
67
+ const next = { ...own, ...patch };
68
+ for (const key of Object.keys(patch))
69
+ if (patch[key] === undefined)
70
+ delete next[key];
71
+ onRole(role, tidy(next), commit);
72
+ };
73
+ const info = roleInfo(role);
74
+ return _jsxs("div", { className: `wb-role ${open === role ? 'is-open' : ''}`, role: "group", "aria-label": info.label, children: [_jsxs("div", { className: "wb-role-main", children: [_jsxs("div", { className: "wb-role-copy", children: [_jsx("strong", { children: info.label }), !compact && _jsx("small", { children: info.hint })] }), _jsxs("button", { type: "button", className: `wb-role-font ${label.inherited ? 'is-inherited' : ''}`, onClick: () => setBrowsing(role), "aria-label": label.inherited ? t('wb.fonts.roleInherited', { role: info.label, font: label.name }) : t('wb.fonts.roleOwn', { role: info.label, font: label.name }), children: [_jsx("span", { className: "wb-role-sample", style: { fontFamily: label.stack, fontWeight: own.weight, letterSpacing: own.tracking !== undefined ? `${own.tracking}em` : undefined, fontVariantNumeric: own.tabular ? 'tabular-nums' : undefined }, children: role === 'numbers' ? `${formatNumber(1284)} · ${formatNumber(3200, { notation: 'compact' })}` : role === 'mono' ? 'const x = 42;' : label.name }), _jsxs("span", { className: "wb-role-name", children: [label.inherited ? t('wb.fonts.inherits', { font: label.name }) : label.name, own.source === 'google' && _jsx("em", { children: "Google" })] })] }), _jsxs("div", { className: "wb-role-actions", children: [role !== 'interface' && _jsx("button", { type: "button", className: `wb-role-tune ${tuned ? 'is-tuned' : ''}`, "aria-expanded": open === role, "aria-label": t('wb.fonts.fineTune', { role: info.label }), title: t('wb.fonts.fineTuneTitle'), onClick: () => setOpen(open === role ? null : role), children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", "aria-hidden": "true", children: _jsx("path", { d: "M3 5h6m3 0h1M3 11h1m3 0h6M9 3.5v3M4 9.5v3", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) }), value !== 'inherit' && _jsx(Button, { size: "sm", tone: "ghost", onClick: () => onRole(role, 'inherit'), title: t('wb.fonts.inheritAgain'), children: t('wb.common.reset') })] })] }), open === role && role !== 'interface' && _jsxs("div", { className: "wb-role-tuning", children: [_jsxs("label", { children: [_jsx("span", { children: t('wb.fonts.weight') }), _jsx(Select, { label: t('wb.fonts.roleWeight', { role: info.label }), value: String(own.weight ?? 'auto'), width: 130, options: [{ value: 'auto', label: t('wb.fonts.asSite') }, ...WEIGHTS.map(w => ({ value: String(w), label: String(w), style: { fontWeight: w } }))], onChange: v => set({ weight: v === 'auto' ? undefined : Number(v) }) })] }), _jsxs("label", { children: [_jsx("span", { children: t('wb.fonts.size') }), _jsx(Slider, { label: t('wb.fonts.roleSize', { role: info.label }), min: ROLE_LIMITS.size[0] * 100, max: ROLE_LIMITS.size[1] * 100, step: 1, value: Math.round((own.size ?? 1) * 100), format: v => t('wb.appearance.percent', { value: v / 100 }), onChange: v => set({ size: v === 100 ? undefined : v / 100 }, false), onCommit: v => set({ size: v === 100 ? undefined : v / 100 }) })] }), _jsxs("label", { children: [_jsx("span", { children: t('wb.fonts.spacing') }), _jsx(Slider, { label: t('wb.fonts.roleSpacing', { role: info.label }), min: ROLE_LIMITS.tracking[0] * 1000, max: ROLE_LIMITS.tracking[1] * 1000, step: 2, value: Math.round((own.tracking ?? 0) * 1000), format: v => `${formatNumber(v / 1000, { minimumFractionDigits: 3, maximumFractionDigits: 3 })} em`, onChange: v => set({ tracking: v === 0 ? undefined : v / 1000 }, false), onCommit: v => set({ tracking: v === 0 ? undefined : v / 1000 }) })] }), _jsxs("label", { className: "is-inline", children: [_jsx("span", { children: t('wb.fonts.tabular') }), _jsx(Toggle, { label: t('wb.fonts.roleTabular', { role: info.label }), checked: !!own.tabular, onChange: tabular => set({ tabular: tabular || undefined }) })] })] })] }, role);
75
+ }), browsing && _jsx(FontBrowser, { role: roleInfo(browsing).label, current: spec(font.roles[browsing]).family[0] ?? null, onPick: choice => pick(browsing, choice), onClose: () => setBrowsing(null) })] });
76
+ }
77
+ //# sourceMappingURL=FontRoles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontRoles.js","sourceRoot":"","sources":["../../../../../../../shell/src/panel/fonts/FontRoles.tsx"],"names":[],"mappings":"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","sourcesContent":["// \"Which font goes where\": one row per font role. Every role inherits the interface font until it\n// is given its own (from Google Fonts, the bundled Geist fonts or an installed system font), and\n// every role but the interface can fine-tune weight, size, letter spacing and tabular figures.\nimport { useEffect, useState } from 'react';\nimport { FONT_ROLE_NAMES, ROLE_LIMITS, fontStack, sanitizeFonts, type FontRole, type FontRoleName, type FontRoleSpec, type FontSpec } from '../../../../runtime/src/themeSpec.ts';\nimport { useT } from '../../frame/hooks.ts';\nimport { formatNumber, t, tx } from '../../frame/i18n.ts';\nimport { Button, Select, Slider, Toggle } from '../controls.tsx';\nimport { panelSite, panelThemes } from '../site.ts';\nimport { themeStore, useThemeState } from '../themes.ts';\nimport { FontBrowser, type FontPick } from './FontBrowser.tsx';\nimport '../builder.css';\n\n/** A font role's name and hint in the active language (`fonts.role.<role>.label/.hint`). */\nexport const roleInfo = (role: FontRoleName) => ({ label: tx(`wb.fonts.role.${role}.label`), hint: tx(`wb.fonts.role.${role}.hint`) });\n\nconst WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900];\nconst spec = (role: FontRole): FontRoleSpec => role === 'inherit' ? { family: [] } : role;\nconst tidy = (next: FontRoleSpec): FontRole => Object.keys(next).length === 1 && !next.family.length ? 'inherit' : next;\n\n/** The name a role shows: its own first family, or where it inherits from. */\nexport function roleLabel(font: FontSpec, role: FontRoleName): { name: string; inherited: boolean; stack?: string } {\n const own = font.roles[role];\n if (own !== 'inherit' && own.family.length) return { name: own.family[0]!, inherited: false, stack: fontStack(own.family) };\n const siteFont = panelThemes().siteFont;\n if (role === 'interface') return { name: siteFont, inherited: true };\n if (role === 'mono') return { name: t('wb.fonts.monospace'), inherited: true, stack: fontStack(['Cascadia Mono', 'Consolas', 'ui-monospace', 'monospace']) };\n const base = font.roles.interface;\n if (base !== 'inherit' && base.family.length) return { name: base.family[0]!, inherited: true, stack: fontStack(base.family) };\n return { name: role === 'chrome' ? `Geist (${panelSite().brand.name})` : siteFont, inherited: true };\n}\n\n/** Loads the Google fonts a font spec names into the panel so its labels render in them. */\nexport function useShellFonts(font: FontSpec) {\n const { fonts } = useThemeState();\n const { ensureShellFont, isInstalled } = themeStore();\n useEffect(() => {\n for (const role of FONT_ROLE_NAMES) {\n const value = font.roles[role];\n if (value !== 'inherit' && value.source === 'google' && value.family[0] && isInstalled(value.family[0])) void ensureShellFont(value.family[0]);\n }\n }, [font, fonts]);\n}\n\nexport function FontRoles({ font, onRole, compact }: { font: FontSpec; onRole(role: FontRoleName, next: FontRole, commit?: boolean): void; compact?: boolean }) {\n const t = useT();\n const [browsing, setBrowsing] = useState<FontRoleName | null>(null);\n const [open, setOpen] = useState<FontRoleName | null>(null);\n useShellFonts(font);\n const pick = (role: FontRoleName, choice: FontPick) => {\n const current = spec(font.roles[role]);\n const next: FontRoleSpec = { ...current, family: sanitizeFonts(choice.family) };\n if (choice.source) next.source = choice.source; else delete next.source;\n onRole(role, tidy(next));\n setBrowsing(null);\n };\n return <div className={`wb-roles ${compact ? 'is-compact' : ''}`}>\n {FONT_ROLE_NAMES.map(role => {\n const label = roleLabel(font, role);\n const value = font.roles[role];\n const own = spec(value);\n const tuned = role !== 'interface' && (own.weight !== undefined || own.size !== undefined || own.tracking !== undefined || !!own.tabular);\n const set = (patch: Partial<FontRoleSpec>, commit = true) => {\n const next: FontRoleSpec = { ...own, ...patch };\n for (const key of Object.keys(patch) as Array<keyof FontRoleSpec>) if (patch[key] === undefined) delete next[key];\n onRole(role, tidy(next), commit);\n };\n const info = roleInfo(role);\n return <div key={role} className={`wb-role ${open === role ? 'is-open' : ''}`} role=\"group\" aria-label={info.label}>\n <div className=\"wb-role-main\">\n <div className=\"wb-role-copy\">\n <strong>{info.label}</strong>\n {!compact && <small>{info.hint}</small>}\n </div>\n <button type=\"button\" className={`wb-role-font ${label.inherited ? 'is-inherited' : ''}`} onClick={() => setBrowsing(role)}\n aria-label={label.inherited ? t('wb.fonts.roleInherited', { role: info.label, font: label.name }) : t('wb.fonts.roleOwn', { role: info.label, font: label.name })}>\n <span className=\"wb-role-sample\" style={{ fontFamily: label.stack, fontWeight: own.weight, letterSpacing: own.tracking !== undefined ? `${own.tracking}em` : undefined, fontVariantNumeric: own.tabular ? 'tabular-nums' : undefined }}>\n {role === 'numbers' ? `${formatNumber(1284)} · ${formatNumber(3200, { notation: 'compact' })}` : role === 'mono' ? 'const x = 42;' : label.name}\n </span>\n <span className=\"wb-role-name\">{label.inherited ? t('wb.fonts.inherits', { font: label.name }) : label.name}{own.source === 'google' && <em>Google</em>}</span>\n </button>\n <div className=\"wb-role-actions\">\n {role !== 'interface' && <button type=\"button\" className={`wb-role-tune ${tuned ? 'is-tuned' : ''}`} aria-expanded={open === role} aria-label={t('wb.fonts.fineTune', { role: info.label })} title={t('wb.fonts.fineTuneTitle')}\n onClick={() => setOpen(open === role ? null : role)}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M3 5h6m3 0h1M3 11h1m3 0h6M9 3.5v3M4 9.5v3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\"/></svg>\n </button>}\n {value !== 'inherit' && <Button size=\"sm\" tone=\"ghost\" onClick={() => onRole(role, 'inherit')} title={t('wb.fonts.inheritAgain')}>{t('wb.common.reset')}</Button>}\n </div>\n </div>\n {open === role && role !== 'interface' && <div className=\"wb-role-tuning\">\n <label><span>{t('wb.fonts.weight')}</span>\n <Select label={t('wb.fonts.roleWeight', { role: info.label })} value={String(own.weight ?? 'auto')} width={130}\n options={[{ value: 'auto', label: t('wb.fonts.asSite') }, ...WEIGHTS.map(w => ({ value: String(w), label: String(w), style: { fontWeight: w } }))]}\n onChange={v => set({ weight: v === 'auto' ? undefined : Number(v) })}/></label>\n <label><span>{t('wb.fonts.size')}</span>\n <Slider label={t('wb.fonts.roleSize', { role: info.label })} min={ROLE_LIMITS.size[0] * 100} max={ROLE_LIMITS.size[1] * 100} step={1} value={Math.round((own.size ?? 1) * 100)} format={v => t('wb.appearance.percent', { value: v / 100 })}\n onChange={v => set({ size: v === 100 ? undefined : v / 100 }, false)} onCommit={v => set({ size: v === 100 ? undefined : v / 100 })}/></label>\n <label><span>{t('wb.fonts.spacing')}</span>\n <Slider label={t('wb.fonts.roleSpacing', { role: info.label })} min={ROLE_LIMITS.tracking[0] * 1000} max={ROLE_LIMITS.tracking[1] * 1000} step={2} value={Math.round((own.tracking ?? 0) * 1000)} format={v => `${formatNumber(v / 1000, { minimumFractionDigits: 3, maximumFractionDigits: 3 })} em`}\n onChange={v => set({ tracking: v === 0 ? undefined : v / 1000 }, false)} onCommit={v => set({ tracking: v === 0 ? undefined : v / 1000 })}/></label>\n <label className=\"is-inline\"><span>{t('wb.fonts.tabular')}</span><Toggle label={t('wb.fonts.roleTabular', { role: info.label })} checked={!!own.tabular} onChange={tabular => set({ tabular: tabular || undefined })}/></label>\n </div>}\n </div>;\n })}\n {browsing && <FontBrowser role={roleInfo(browsing).label} current={spec(font.roles[browsing]).family[0] ?? null}\n onPick={choice => pick(browsing, choice)} onClose={() => setBrowsing(null)}/>}\n </div>;\n}\n"]}
@@ -0,0 +1,37 @@
1
+ export type Category = 'sans' | 'serif' | 'display' | 'handwriting' | 'mono';
2
+ export type CatalogFont = {
3
+ family: string;
4
+ category: Category;
5
+ axis: [number, number] | null;
6
+ weights: number[];
7
+ rank: number;
8
+ };
9
+ export type Weights = {
10
+ kind: 'range';
11
+ min: number;
12
+ max: number;
13
+ } | {
14
+ kind: 'list';
15
+ values: number[];
16
+ };
17
+ /** Filter chips; labels are `fonts.category.<id>` (short) and `fonts.categoryName.<id>` (full) in the catalogs. */
18
+ export declare const CATEGORIES: Array<Category | 'all'>;
19
+ export declare function parseCatalog(raw: unknown): CatalogFont[];
20
+ /** The bundled catalog, loaded on first use (it is ~90 KB, so it stays out of the shell's first paint). */
21
+ export declare function loadCatalog(): Promise<CatalogFont[]>;
22
+ /** Search by name (prefix matches first, then popularity), within a category and optionally only installed ones. */
23
+ export declare function searchFonts(fonts: CatalogFont[], options: {
24
+ query?: string;
25
+ category?: Category | 'all';
26
+ only?: Set<string>;
27
+ }): CatalogFont[];
28
+ /** What to download by default: the whole weight axis of a variable font, else regular and bold (or the nearest). */
29
+ export declare function defaultWeights(font: CatalogFont): Weights;
30
+ /** The weights a font can be previewed at (every 100 inside the axis, or the static weights). */
31
+ export declare const availableWeights: (font: CatalogFont) => number[];
32
+ /** A stack that falls back sensibly while the font loads, or where it lacks a glyph. */
33
+ export declare function stackFor(font: Pick<CatalogFont, 'family' | 'category'>): string[];
34
+ export declare const weightsLabel: (weights: Weights) => string;
35
+ export declare const bytesLabel: (bytes: number) => string;
36
+ /** Google Fonts' own page for a family (its license and designers), opened in the browser. */
37
+ export declare const specimenUrl: (family: string) => string;
@@ -0,0 +1,68 @@
1
+ // The Google Fonts catalog the font browser shows: an offline snapshot (googleFontsCatalog.json,
2
+ // regenerated by packages/shell/scripts/google-fonts-catalog.mjs) of family names, categories and
3
+ // weights. The list itself is never fetched by the app; only the font files the owner picks are
4
+ // (natively). Pure helpers, shared with the tests.
5
+ import { textLocale } from "../../frame/i18n.js";
6
+ /** Filter chips; labels are `fonts.category.<id>` (short) and `fonts.categoryName.<id>` (full) in the catalogs. */
7
+ export const CATEGORIES = ['all', 'sans', 'serif', 'display', 'handwriting', 'mono'];
8
+ const KNOWN = new Set(['sans', 'serif', 'display', 'handwriting', 'mono']);
9
+ const NAME = /^[A-Za-z0-9]+( [A-Za-z0-9]+)*$/;
10
+ export function parseCatalog(raw) {
11
+ const families = raw?.families;
12
+ if (!Array.isArray(families))
13
+ return [];
14
+ return families
15
+ .filter(([family, category, , weights]) => typeof family === 'string' && NAME.test(family) && family.length <= 48 && KNOWN.has(category) && Array.isArray(weights))
16
+ .map(([family, category, axis, weights, rank]) => ({
17
+ family, category: category,
18
+ axis: Array.isArray(axis) && axis.length === 2 ? [axis[0], axis[1]] : null,
19
+ weights: weights.filter(w => Number.isInteger(w) && w >= 100 && w <= 1000), rank: Number(rank) || 9999,
20
+ }));
21
+ }
22
+ let loaded = null;
23
+ /** The bundled catalog, loaded on first use (it is ~90 KB, so it stays out of the shell's first paint). */
24
+ export function loadCatalog() {
25
+ loaded ??= import('./googleFontsCatalog.json').then(module => parseCatalog(module.default));
26
+ return loaded;
27
+ }
28
+ /** Search by name (prefix matches first, then popularity), within a category and optionally only installed ones. */
29
+ export function searchFonts(fonts, options) {
30
+ const query = (options.query ?? '').trim().toLowerCase();
31
+ const list = fonts.filter(font => (!options.category || options.category === 'all' || font.category === options.category)
32
+ && (!options.only || options.only.has(font.family))
33
+ && (!query || font.family.toLowerCase().includes(query)));
34
+ if (!query)
35
+ return list.sort((a, b) => a.rank - b.rank);
36
+ const score = (font) => {
37
+ const name = font.family.toLowerCase();
38
+ return name === query ? 0 : name.startsWith(query) ? 1 : name.split(' ').some(word => word.startsWith(query)) ? 2 : 3;
39
+ };
40
+ return list.sort((a, b) => score(a) - score(b) || a.rank - b.rank);
41
+ }
42
+ /** What to download by default: the whole weight axis of a variable font, else regular and bold (or the nearest). */
43
+ export function defaultWeights(font) {
44
+ if (font.axis)
45
+ return { kind: 'range', min: font.axis[0], max: font.axis[1] };
46
+ const pick = (target) => font.weights.reduce((best, w) => Math.abs(w - target) < Math.abs(best - target) ? w : best, font.weights[0] ?? 400);
47
+ return { kind: 'list', values: [...new Set([pick(400), pick(700)])].sort((a, b) => a - b) };
48
+ }
49
+ /** The weights a font can be previewed at (every 100 inside the axis, or the static weights). */
50
+ export const availableWeights = (font) => font.axis
51
+ ? Array.from({ length: 9 }, (_, i) => (i + 1) * 100).filter(w => w >= font.axis[0] && w <= font.axis[1])
52
+ : font.weights;
53
+ /** A stack that falls back sensibly while the font loads, or where it lacks a glyph. */
54
+ export function stackFor(font) {
55
+ const fallback = {
56
+ sans: ['system-ui', 'sans-serif'], serif: ['Georgia', 'serif'], display: ['system-ui', 'sans-serif'],
57
+ handwriting: ['cursive'], mono: ['ui-monospace', 'monospace'],
58
+ };
59
+ return [font.family, ...fallback[font.category]];
60
+ }
61
+ export const weightsLabel = (weights) => weights.kind === 'range' ? `${weights.min}–${weights.max}` : weights.values.join(', ');
62
+ const numberLocale = () => textLocale().split('-x-')[0] || 'en';
63
+ export const bytesLabel = (bytes) => bytes >= 1_000_000
64
+ ? `${new Intl.NumberFormat(numberLocale(), { minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(bytes / 1_000_000)} MB`
65
+ : `${new Intl.NumberFormat(numberLocale()).format(Math.max(1, Math.round(bytes / 1000)))} KB`;
66
+ /** Google Fonts' own page for a family (its license and designers), opened in the browser. */
67
+ export const specimenUrl = (family) => `https://fonts.google.com/specimen/${family.replace(/ /g, '+')}`;
68
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../../../../shell/src/panel/fonts/catalog.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,kGAAkG;AAClG,gGAAgG;AAChG,mDAAmD;AAEnD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMjD,mHAAmH;AACnH,MAAM,CAAC,MAAM,UAAU,GAA4B,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;AAG9G,MAAM,KAAK,GAAG,IAAI,GAAG,CAAW,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;AACrF,MAAM,IAAI,GAAG,gCAAgC,CAAC;AAE9C,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,MAAM,QAAQ,GAAI,GAAkB,EAAE,QAAQ,CAAC;IAC/C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,OAAO,QAAQ;SACZ,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,AAAD,EAAG,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,QAAoB,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;SAC9K,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACjD,MAAM,EAAE,QAAQ,EAAE,QAAoB;QACtC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAqB,CAAC,CAAC,CAAC,IAAI;QAC9F,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI;KACvG,CAAC,CAAC,CAAC;AACR,CAAC;AAED,IAAI,MAAM,GAAkC,IAAI,CAAC;AACjD,2GAA2G;AAC3G,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,MAAM,CAAC,2BAA2B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5F,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,WAAW,CAAC,KAAoB,EAAE,OAA4E;IAC5H,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACzD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAC/B,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ,CAAC;WACpF,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;WAChD,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,CAAC,IAAiB,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACvC,OAAO,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxH,CAAC,CAAC;IACF,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACrE,CAAC;AAED,qHAAqH;AACrH,MAAM,UAAU,cAAc,CAAC,IAAiB;IAC9C,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IACrJ,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;AAC9F,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAiB,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI;IAC9D,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,IAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAK,CAAC,CAAC,CAAC,CAAC;IAC1G,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAEjB,wFAAwF;AACxF,MAAM,UAAU,QAAQ,CAAC,IAA8C;IACrE,MAAM,QAAQ,GAA+B;QAC3C,IAAI,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC;QACpG,WAAW,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,cAAc,EAAE,WAAW,CAAC;KAC9D,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzI,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAChE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,IAAI,SAAS;IAC7D,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK;IACjI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AAChG,8FAA8F;AAC9F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,qCAAqC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC","sourcesContent":["// The Google Fonts catalog the font browser shows: an offline snapshot (googleFontsCatalog.json,\n// regenerated by packages/shell/scripts/google-fonts-catalog.mjs) of family names, categories and\n// weights. The list itself is never fetched by the app; only the font files the owner picks are\n// (natively). Pure helpers, shared with the tests.\n\nimport { textLocale } from '../../frame/i18n.ts';\n\nexport type Category = 'sans' | 'serif' | 'display' | 'handwriting' | 'mono';\nexport type CatalogFont = { family: string; category: Category; axis: [number, number] | null; weights: number[]; rank: number };\nexport type Weights = { kind: 'range'; min: number; max: number } | { kind: 'list'; values: number[] };\n\n/** Filter chips; labels are `fonts.category.<id>` (short) and `fonts.categoryName.<id>` (full) in the catalogs. */\nexport const CATEGORIES: Array<Category | 'all'> = ['all', 'sans', 'serif', 'display', 'handwriting', 'mono'];\n\ntype Raw = { families: Array<[string, string, [number, number] | null, number[], number]> };\nconst KNOWN = new Set<Category>(['sans', 'serif', 'display', 'handwriting', 'mono']);\nconst NAME = /^[A-Za-z0-9]+( [A-Za-z0-9]+)*$/;\n\nexport function parseCatalog(raw: unknown): CatalogFont[] {\n const families = (raw as Raw | null)?.families;\n if (!Array.isArray(families)) return [];\n return families\n .filter(([family, category, , weights]) => typeof family === 'string' && NAME.test(family) && family.length <= 48 && KNOWN.has(category as Category) && Array.isArray(weights))\n .map(([family, category, axis, weights, rank]) => ({\n family, category: category as Category,\n axis: Array.isArray(axis) && axis.length === 2 ? [axis[0], axis[1]] as [number, number] : null,\n weights: weights.filter(w => Number.isInteger(w) && w >= 100 && w <= 1000), rank: Number(rank) || 9999,\n }));\n}\n\nlet loaded: Promise<CatalogFont[]> | null = null;\n/** The bundled catalog, loaded on first use (it is ~90 KB, so it stays out of the shell's first paint). */\nexport function loadCatalog(): Promise<CatalogFont[]> {\n loaded ??= import('./googleFontsCatalog.json').then(module => parseCatalog(module.default));\n return loaded;\n}\n\n/** Search by name (prefix matches first, then popularity), within a category and optionally only installed ones. */\nexport function searchFonts(fonts: CatalogFont[], options: { query?: string; category?: Category | 'all'; only?: Set<string> }): CatalogFont[] {\n const query = (options.query ?? '').trim().toLowerCase();\n const list = fonts.filter(font =>\n (!options.category || options.category === 'all' || font.category === options.category)\n && (!options.only || options.only.has(font.family))\n && (!query || font.family.toLowerCase().includes(query)));\n if (!query) return list.sort((a, b) => a.rank - b.rank);\n const score = (font: CatalogFont) => {\n const name = font.family.toLowerCase();\n return name === query ? 0 : name.startsWith(query) ? 1 : name.split(' ').some(word => word.startsWith(query)) ? 2 : 3;\n };\n return list.sort((a, b) => score(a) - score(b) || a.rank - b.rank);\n}\n\n/** What to download by default: the whole weight axis of a variable font, else regular and bold (or the nearest). */\nexport function defaultWeights(font: CatalogFont): Weights {\n if (font.axis) return { kind: 'range', min: font.axis[0], max: font.axis[1] };\n const pick = (target: number) => font.weights.reduce((best, w) => Math.abs(w - target) < Math.abs(best - target) ? w : best, font.weights[0] ?? 400);\n return { kind: 'list', values: [...new Set([pick(400), pick(700)])].sort((a, b) => a - b) };\n}\n\n/** The weights a font can be previewed at (every 100 inside the axis, or the static weights). */\nexport const availableWeights = (font: CatalogFont) => font.axis\n ? Array.from({ length: 9 }, (_, i) => (i + 1) * 100).filter(w => w >= font.axis![0] && w <= font.axis![1])\n : font.weights;\n\n/** A stack that falls back sensibly while the font loads, or where it lacks a glyph. */\nexport function stackFor(font: Pick<CatalogFont, 'family' | 'category'>): string[] {\n const fallback: Record<Category, string[]> = {\n sans: ['system-ui', 'sans-serif'], serif: ['Georgia', 'serif'], display: ['system-ui', 'sans-serif'],\n handwriting: ['cursive'], mono: ['ui-monospace', 'monospace'],\n };\n return [font.family, ...fallback[font.category]];\n}\n\nexport const weightsLabel = (weights: Weights) => weights.kind === 'range' ? `${weights.min}–${weights.max}` : weights.values.join(', ');\nconst numberLocale = () => textLocale().split('-x-')[0] || 'en';\nexport const bytesLabel = (bytes: number) => bytes >= 1_000_000\n ? `${new Intl.NumberFormat(numberLocale(), { minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(bytes / 1_000_000)} MB`\n : `${new Intl.NumberFormat(numberLocale()).format(Math.max(1, Math.round(bytes / 1000)))} KB`;\n/** Google Fonts' own page for a family (its license and designers), opened in the browser. */\nexport const specimenUrl = (family: string) => `https://fonts.google.com/specimen/${family.replace(/ /g, '+')}`;\n"]}