waybetter 0.1.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -6
- package/bin/waybetter.mjs +46 -0
- package/build/runtime.mjs +105 -0
- package/cli/buildenv.mjs +130 -0
- package/cli/dev.mjs +97 -0
- package/cli/i18n.mjs +382 -0
- package/cli/manifests.mjs +383 -0
- package/cli/privacy.mjs +768 -0
- package/cli/release.mjs +444 -0
- package/cli/remote.mjs +260 -0
- package/cli/store.mjs +326 -0
- package/cli/strings.mjs +121 -0
- package/dist/runtime/column.d.ts +93 -0
- package/dist/runtime/column.js +451 -0
- package/dist/runtime/column.js.map +1 -0
- package/dist/runtime/commandReport.d.ts +19 -0
- package/dist/runtime/commandReport.js +47 -0
- package/dist/runtime/commandReport.js.map +1 -0
- package/dist/runtime/commands.d.ts +72 -0
- package/dist/runtime/commands.js +214 -0
- package/dist/runtime/commands.js.map +1 -0
- package/dist/runtime/devErrors.d.ts +16 -0
- package/dist/runtime/devErrors.js +30 -0
- package/dist/runtime/devErrors.js.map +1 -0
- package/dist/runtime/domHub.d.ts +21 -0
- package/dist/runtime/domHub.js +139 -4
- package/dist/runtime/domHub.js.map +1 -1
- package/dist/runtime/featureModules.d.ts +157 -0
- package/dist/runtime/featureModules.js +484 -0
- package/dist/runtime/featureModules.js.map +1 -0
- package/dist/runtime/featureTable.d.ts +144 -0
- package/dist/runtime/featureTable.js +223 -0
- package/dist/runtime/featureTable.js.map +1 -0
- package/dist/runtime/fonts.d.ts +22 -0
- package/dist/runtime/fonts.js +72 -0
- package/dist/runtime/fonts.js.map +1 -0
- package/dist/runtime/i18n.d.ts +138 -0
- package/dist/runtime/i18n.js +614 -0
- package/dist/runtime/i18n.js.map +1 -0
- package/dist/runtime/i18nCheck.d.ts +30 -0
- package/dist/runtime/i18nCheck.js +224 -0
- package/dist/runtime/i18nCheck.js.map +1 -0
- package/dist/runtime/pageLang.d.ts +8 -0
- package/dist/runtime/pageLang.js +64 -0
- package/dist/runtime/pageLang.js.map +1 -0
- package/dist/runtime/pageStrings.d.ts +35 -0
- package/dist/runtime/pageStrings.js +76 -0
- package/dist/runtime/pageStrings.js.map +1 -0
- package/dist/runtime/panelButton.d.ts +33 -0
- package/dist/runtime/panelButton.js +83 -0
- package/dist/runtime/panelButton.js.map +1 -0
- package/dist/runtime/permissions.d.ts +47 -0
- package/dist/runtime/permissions.js +141 -0
- package/dist/runtime/permissions.js.map +1 -0
- package/dist/runtime/pluginApi.d.ts +51 -2
- package/dist/runtime/pluginApi.js +137 -22
- package/dist/runtime/pluginApi.js.map +1 -1
- package/dist/runtime/pluginI18n.d.ts +29 -0
- package/dist/runtime/pluginI18n.js +119 -0
- package/dist/runtime/pluginI18n.js.map +1 -0
- package/dist/runtime/settingsForm.d.ts +66 -0
- package/dist/runtime/settingsForm.js +114 -0
- package/dist/runtime/settingsForm.js.map +1 -0
- package/dist/runtime/site.d.ts +5 -0
- package/dist/runtime/site.js +1 -1
- package/dist/runtime/site.js.map +1 -1
- package/dist/runtime/siteRuntime.d.ts +144 -0
- package/dist/runtime/siteRuntime.js +175 -0
- package/dist/runtime/siteRuntime.js.map +1 -0
- package/dist/runtime/stringPackHook.d.ts +84 -0
- package/dist/runtime/stringPackHook.js +220 -0
- package/dist/runtime/stringPackHook.js.map +1 -0
- package/dist/runtime/stringPackTranslate.d.ts +59 -0
- package/dist/runtime/stringPackTranslate.js +264 -0
- package/dist/runtime/stringPackTranslate.js.map +1 -0
- package/dist/runtime/stringPacks.d.ts +200 -0
- package/dist/runtime/stringPacks.js +474 -0
- package/dist/runtime/stringPacks.js.map +1 -0
- package/dist/runtime/styles.d.ts +15 -0
- package/dist/runtime/styles.js +81 -0
- package/dist/runtime/styles.js.map +1 -0
- package/dist/runtime/textNet.d.ts +15 -0
- package/dist/runtime/textNet.js +131 -0
- package/dist/runtime/textNet.js.map +1 -0
- package/dist/runtime/themeApi.d.ts +121 -0
- package/dist/runtime/themeApi.js +220 -0
- package/dist/runtime/themeApi.js.map +1 -0
- package/dist/runtime/themeChoice.d.ts +52 -0
- package/dist/runtime/themeChoice.js +69 -0
- package/dist/runtime/themeChoice.js.map +1 -0
- package/dist/runtime/themeComponents.d.ts +435 -0
- package/dist/runtime/themeComponents.js +463 -0
- package/dist/runtime/themeComponents.js.map +1 -0
- package/dist/runtime/themeDecor.d.ts +73 -0
- package/dist/runtime/themeDecor.js +131 -0
- package/dist/runtime/themeDecor.js.map +1 -0
- package/dist/runtime/themeDoctor.d.ts +11 -0
- package/dist/runtime/themeDoctor.js +51 -0
- package/dist/runtime/themeDoctor.js.map +1 -0
- package/dist/runtime/themeIcons.d.ts +130 -0
- package/dist/runtime/themeIcons.js +263 -0
- package/dist/runtime/themeIcons.js.map +1 -0
- package/dist/runtime/themeRuntime.d.ts +100 -0
- package/dist/runtime/themeRuntime.js +497 -0
- package/dist/runtime/themeRuntime.js.map +1 -0
- package/dist/runtime/themeSchema.d.ts +10 -0
- package/dist/runtime/themeSchema.js +150 -0
- package/dist/runtime/themeSchema.js.map +1 -0
- package/dist/runtime/themeSpec.d.ts +259 -0
- package/dist/runtime/themeSpec.js +439 -0
- package/dist/runtime/themeSpec.js.map +1 -0
- package/dist/runtime/themeTokens.d.ts +12 -0
- package/dist/runtime/themeTokens.js +14 -6
- package/dist/runtime/themeTokens.js.map +1 -1
- package/dist/runtime/themeVariants.d.ts +30 -0
- package/dist/runtime/themeVariants.js +53 -0
- package/dist/runtime/themeVariants.js.map +1 -0
- package/dist/runtime/ui.d.ts +192 -0
- package/dist/runtime/ui.js +926 -0
- package/dist/runtime/ui.js.map +1 -0
- package/dist/shell/InstallDialog.d.ts +40 -0
- package/dist/shell/InstallDialog.js +170 -0
- package/dist/shell/InstallDialog.js.map +1 -0
- package/dist/shell/StoreView.d.ts +66 -0
- package/dist/shell/StoreView.js +103 -0
- package/dist/shell/StoreView.js.map +1 -0
- package/dist/shell/addressModel.js.map +1 -1
- package/dist/shell/chrome.js.map +1 -1
- package/dist/shell/deckModel.d.ts +117 -0
- package/dist/shell/deckModel.js +267 -0
- package/dist/shell/deckModel.js.map +1 -0
- package/dist/shell/frame/AccountSwitcher.d.ts +42 -0
- package/dist/shell/frame/AccountSwitcher.js +243 -0
- package/dist/shell/frame/AccountSwitcher.js.map +1 -0
- package/dist/shell/frame/AddColumnDialog.d.ts +8 -0
- package/dist/shell/frame/AddColumnDialog.js +81 -0
- package/dist/shell/frame/AddColumnDialog.js.map +1 -0
- package/dist/shell/frame/AppMenu.d.ts +21 -0
- package/dist/shell/frame/AppMenu.js +642 -0
- package/dist/shell/frame/AppMenu.js.map +1 -0
- package/dist/shell/frame/CommandPalette.d.ts +7 -0
- package/dist/shell/frame/CommandPalette.js +118 -0
- package/dist/shell/frame/CommandPalette.js.map +1 -0
- package/dist/shell/frame/DeckView.d.ts +13 -0
- package/dist/shell/frame/DeckView.js +287 -0
- package/dist/shell/frame/DeckView.js.map +1 -0
- package/dist/shell/frame/FindBar.d.ts +10 -0
- package/dist/shell/frame/FindBar.js +108 -0
- package/dist/shell/frame/FindBar.js.map +1 -0
- package/dist/shell/frame/MediaPanel.d.ts +8 -0
- package/dist/shell/frame/MediaPanel.js +76 -0
- package/dist/shell/frame/MediaPanel.js.map +1 -0
- package/dist/shell/frame/NewTabPage.d.ts +9 -0
- package/dist/shell/frame/NewTabPage.js +71 -0
- package/dist/shell/frame/NewTabPage.js.map +1 -0
- package/dist/shell/frame/PaneTheme.d.ts +16 -0
- package/dist/shell/frame/PaneTheme.js +67 -0
- package/dist/shell/frame/PaneTheme.js.map +1 -0
- package/dist/shell/frame/ReportDialog.d.ts +3 -0
- package/dist/shell/frame/ReportDialog.js +95 -0
- package/dist/shell/frame/ReportDialog.js.map +1 -0
- package/dist/shell/frame/Shell.d.ts +8 -0
- package/dist/shell/frame/Shell.js +1131 -0
- package/dist/shell/frame/Shell.js.map +1 -0
- package/dist/shell/frame/Titlebar.d.ts +16 -0
- package/dist/shell/frame/Titlebar.js +77 -0
- package/dist/shell/frame/Titlebar.js.map +1 -0
- package/dist/shell/frame/TitlebarExtras.d.ts +4 -0
- package/dist/shell/frame/TitlebarExtras.js +202 -0
- package/dist/shell/frame/TitlebarExtras.js.map +1 -0
- package/dist/shell/frame/WebPanel.d.ts +4 -0
- package/dist/shell/frame/WebPanel.js +182 -0
- package/dist/shell/frame/WebPanel.js.map +1 -0
- package/dist/shell/frame/accountModel.d.ts +49 -0
- package/dist/shell/frame/accountModel.js +67 -0
- package/dist/shell/frame/accountModel.js.map +1 -0
- package/dist/shell/frame/accountSwitcher.css +91 -0
- package/dist/shell/frame/appI18n.d.ts +44 -0
- package/dist/shell/frame/appI18n.js +64 -0
- package/dist/shell/frame/appI18n.js.map +1 -0
- package/dist/shell/frame/appMenu.css +121 -0
- package/dist/shell/frame/backupModel.d.ts +38 -0
- package/dist/shell/frame/backupModel.js +192 -0
- package/dist/shell/frame/backupModel.js.map +1 -0
- package/dist/shell/frame/boot.d.ts +8 -0
- package/dist/shell/frame/boot.js +35 -0
- package/dist/shell/frame/boot.js.map +1 -0
- package/dist/shell/frame/brand.d.ts +1 -0
- package/dist/shell/frame/brand.js +4 -0
- package/dist/shell/frame/brand.js.map +1 -0
- package/dist/shell/frame/bridge.d.ts +35 -0
- package/dist/shell/frame/bridge.js +70 -0
- package/dist/shell/frame/bridge.js.map +1 -0
- package/dist/shell/frame/chromeTheme.d.ts +29 -0
- package/dist/shell/frame/chromeTheme.js +81 -0
- package/dist/shell/frame/chromeTheme.js.map +1 -0
- package/dist/shell/frame/deck.css +209 -0
- package/dist/shell/frame/deckStore.d.ts +89 -0
- package/dist/shell/frame/deckStore.js +239 -0
- package/dist/shell/frame/deckStore.js.map +1 -0
- package/dist/shell/frame/devHost.d.ts +35 -0
- package/dist/shell/frame/devHost.js +80 -0
- package/dist/shell/frame/devHost.js.map +1 -0
- package/dist/shell/frame/devModel.d.ts +7 -0
- package/dist/shell/frame/devModel.js +17 -0
- package/dist/shell/frame/devModel.js.map +1 -0
- package/dist/shell/frame/diag.d.ts +7 -0
- package/dist/shell/frame/diag.js +39 -0
- package/dist/shell/frame/diag.js.map +1 -0
- package/dist/shell/frame/findBar.css +14 -0
- package/dist/shell/frame/frameMessages.d.ts +248 -0
- package/dist/shell/frame/frameMessages.js +252 -0
- package/dist/shell/frame/frameMessages.js.map +1 -0
- package/dist/shell/frame/hooks.d.ts +39 -0
- package/dist/shell/frame/hooks.js +97 -0
- package/dist/shell/frame/hooks.js.map +1 -0
- package/dist/shell/frame/i18n.d.ts +27 -0
- package/dist/shell/frame/i18n.js +66 -0
- package/dist/shell/frame/i18n.js.map +1 -0
- package/dist/shell/frame/iconPack.d.ts +11 -0
- package/dist/shell/frame/iconPack.js +45 -0
- package/dist/shell/frame/iconPack.js.map +1 -0
- package/dist/shell/frame/icons.d.ts +71 -0
- package/dist/shell/frame/icons.js +75 -0
- package/dist/shell/frame/icons.js.map +1 -0
- package/dist/shell/frame/index.d.ts +34 -0
- package/dist/shell/frame/index.js +43 -0
- package/dist/shell/frame/index.js.map +1 -0
- package/dist/shell/frame/language.d.ts +58 -0
- package/dist/shell/frame/language.js +165 -0
- package/dist/shell/frame/language.js.map +1 -0
- package/dist/shell/frame/mediaModel.d.ts +34 -0
- package/dist/shell/frame/mediaModel.js +53 -0
- package/dist/shell/frame/mediaModel.js.map +1 -0
- package/dist/shell/frame/menuMessages.en.json +54 -0
- package/dist/shell/frame/menuModel.d.ts +277 -0
- package/dist/shell/frame/menuModel.js +293 -0
- package/dist/shell/frame/menuModel.js.map +1 -0
- package/dist/shell/frame/paletteModel.d.ts +139 -0
- package/dist/shell/frame/paletteModel.js +112 -0
- package/dist/shell/frame/paletteModel.js.map +1 -0
- package/dist/shell/frame/paneTheme.css +9 -0
- package/dist/shell/frame/pluginCommandStore.d.ts +23 -0
- package/dist/shell/frame/pluginCommandStore.js +70 -0
- package/dist/shell/frame/pluginCommandStore.js.map +1 -0
- package/dist/shell/frame/reportModel.d.ts +52 -0
- package/dist/shell/frame/reportModel.js +105 -0
- package/dist/shell/frame/reportModel.js.map +1 -0
- package/dist/shell/frame/safeStore.d.ts +7 -0
- package/dist/shell/frame/safeStore.js +40 -0
- package/dist/shell/frame/safeStore.js.map +1 -0
- package/dist/shell/frame/searchInput.d.ts +2 -0
- package/dist/shell/frame/searchInput.js +11 -0
- package/dist/shell/frame/searchInput.js.map +1 -0
- package/dist/shell/frame/shell.css +629 -0
- package/dist/shell/frame/site.d.ts +206 -0
- package/dist/shell/frame/site.js +22 -0
- package/dist/shell/frame/site.js.map +1 -0
- package/dist/shell/frame/state.d.ts +99 -0
- package/dist/shell/frame/state.js +284 -0
- package/dist/shell/frame/state.js.map +1 -0
- package/dist/shell/frame/syncGate.d.ts +10 -0
- package/dist/shell/frame/syncGate.js +36 -0
- package/dist/shell/frame/syncGate.js.map +1 -0
- package/dist/shell/frame/syncHost.d.ts +35 -0
- package/dist/shell/frame/syncHost.js +85 -0
- package/dist/shell/frame/syncHost.js.map +1 -0
- package/dist/shell/frame/tabStill.d.ts +2 -0
- package/dist/shell/frame/tabStill.js +62 -0
- package/dist/shell/frame/tabStill.js.map +1 -0
- package/dist/shell/frame/themeScopes.d.ts +29 -0
- package/dist/shell/frame/themeScopes.js +61 -0
- package/dist/shell/frame/themeScopes.js.map +1 -0
- package/dist/shell/frame/themeStore.d.ts +99 -0
- package/dist/shell/frame/themeStore.js +252 -0
- package/dist/shell/frame/themeStore.js.map +1 -0
- package/dist/shell/frame/windowBinding.d.ts +2 -0
- package/dist/shell/frame/windowBinding.js +7 -0
- package/dist/shell/frame/windowBinding.js.map +1 -0
- package/dist/shell/frame/workspaceModel.d.ts +82 -0
- package/dist/shell/frame/workspaceModel.js +250 -0
- package/dist/shell/frame/workspaceModel.js.map +1 -0
- package/dist/shell/frame/workspaces.css +84 -0
- package/dist/shell/frame/workspaces.d.ts +22 -0
- package/dist/shell/frame/workspaces.js +125 -0
- package/dist/shell/frame/workspaces.js.map +1 -0
- package/dist/shell/frame/zoomStore.d.ts +10 -0
- package/dist/shell/frame/zoomStore.js +65 -0
- package/dist/shell/frame/zoomStore.js.map +1 -0
- package/dist/shell/installController.d.ts +122 -0
- package/dist/shell/installController.js +146 -0
- package/dist/shell/installController.js.map +1 -0
- package/dist/shell/installerMessages.d.ts +30 -0
- package/dist/shell/installerMessages.js +36 -0
- package/dist/shell/installerMessages.js.map +1 -0
- package/dist/shell/linkDrop.js.map +1 -1
- package/dist/shell/messages.d.ts +16 -0
- package/dist/shell/messages.js +27 -0
- package/dist/shell/messages.js.map +1 -0
- package/dist/shell/palette.js.map +1 -1
- package/dist/shell/paneModel.d.ts +22 -0
- package/dist/shell/paneModel.js +24 -1
- package/dist/shell/paneModel.js.map +1 -1
- package/dist/shell/panel/Appearance.d.ts +8 -0
- package/dist/shell/panel/Appearance.js +256 -0
- package/dist/shell/panel/Appearance.js.map +1 -0
- package/dist/shell/panel/BackupPanel.d.ts +5 -0
- package/dist/shell/panel/BackupPanel.js +198 -0
- package/dist/shell/panel/BackupPanel.js.map +1 -0
- package/dist/shell/panel/DeveloperPanel.d.ts +4 -0
- package/dist/shell/panel/DeveloperPanel.js +51 -0
- package/dist/shell/panel/DeveloperPanel.js.map +1 -0
- package/dist/shell/panel/FeatureToggles.d.ts +13 -0
- package/dist/shell/panel/FeatureToggles.js +42 -0
- package/dist/shell/panel/FeatureToggles.js.map +1 -0
- package/dist/shell/panel/Home.d.ts +3 -0
- package/dist/shell/panel/Home.js +23 -0
- package/dist/shell/panel/Home.js.map +1 -0
- package/dist/shell/panel/IconPackInstall.d.ts +15 -0
- package/dist/shell/panel/IconPackInstall.js +41 -0
- package/dist/shell/panel/IconPackInstall.js.map +1 -0
- package/dist/shell/panel/LanguageSettings.d.ts +1 -0
- package/dist/shell/panel/LanguageSettings.js +54 -0
- package/dist/shell/panel/LanguageSettings.js.map +1 -0
- package/dist/shell/panel/MakePanel.d.ts +3 -0
- package/dist/shell/panel/MakePanel.js +237 -0
- package/dist/shell/panel/MakePanel.js.map +1 -0
- package/dist/shell/panel/MarkdownDoc.d.ts +6 -0
- package/dist/shell/panel/MarkdownDoc.js +35 -0
- package/dist/shell/panel/MarkdownDoc.js.map +1 -0
- package/dist/shell/panel/Modes.d.ts +40 -0
- package/dist/shell/panel/Modes.js +270 -0
- package/dist/shell/panel/Modes.js.map +1 -0
- package/dist/shell/panel/NavIcon.d.ts +4 -0
- package/dist/shell/panel/NavIcon.js +6 -0
- package/dist/shell/panel/NavIcon.js.map +1 -0
- package/dist/shell/panel/Panel.d.ts +7 -0
- package/dist/shell/panel/Panel.js +139 -0
- package/dist/shell/panel/Panel.js.map +1 -0
- package/dist/shell/panel/PluginFeatures.d.ts +24 -0
- package/dist/shell/panel/PluginFeatures.js +165 -0
- package/dist/shell/panel/PluginFeatures.js.map +1 -0
- package/dist/shell/panel/Plugins.d.ts +33 -0
- package/dist/shell/panel/Plugins.js +112 -0
- package/dist/shell/panel/Plugins.js.map +1 -0
- package/dist/shell/panel/PowerSettings.d.ts +4 -0
- package/dist/shell/panel/PowerSettings.js +52 -0
- package/dist/shell/panel/PowerSettings.js.map +1 -0
- package/dist/shell/panel/Settings.d.ts +23 -0
- package/dist/shell/panel/Settings.js +116 -0
- package/dist/shell/panel/Settings.js.map +1 -0
- package/dist/shell/panel/ShareSetup.d.ts +8 -0
- package/dist/shell/panel/ShareSetup.js +130 -0
- package/dist/shell/panel/ShareSetup.js.map +1 -0
- package/dist/shell/panel/StoreSection.d.ts +6 -0
- package/dist/shell/panel/StoreSection.js +48 -0
- package/dist/shell/panel/StoreSection.js.map +1 -0
- package/dist/shell/panel/StringPacks.d.ts +11 -0
- package/dist/shell/panel/StringPacks.js +106 -0
- package/dist/shell/panel/StringPacks.js.map +1 -0
- package/dist/shell/panel/ThemeBuilder.d.ts +5 -0
- package/dist/shell/panel/ThemeBuilder.js +205 -0
- package/dist/shell/panel/ThemeBuilder.js.map +1 -0
- package/dist/shell/panel/backup.css +34 -0
- package/dist/shell/panel/builder.css +232 -0
- package/dist/shell/panel/builderModel.d.ts +55 -0
- package/dist/shell/panel/builderModel.js +95 -0
- package/dist/shell/panel/builderModel.js.map +1 -0
- package/dist/shell/panel/compare.d.ts +10 -0
- package/dist/shell/panel/compare.js +51 -0
- package/dist/shell/panel/compare.js.map +1 -0
- package/dist/shell/panel/controls.d.ts +135 -0
- package/dist/shell/panel/controls.js +213 -0
- package/dist/shell/panel/controls.js.map +1 -0
- package/dist/shell/panel/featureModel.d.ts +69 -0
- package/dist/shell/panel/featureModel.js +79 -0
- package/dist/shell/panel/featureModel.js.map +1 -0
- package/dist/shell/panel/fonts/FontBrowser.d.ts +10 -0
- package/dist/shell/panel/fonts/FontBrowser.js +189 -0
- package/dist/shell/panel/fonts/FontBrowser.js.map +1 -0
- package/dist/shell/panel/fonts/FontRoles.d.ts +20 -0
- package/dist/shell/panel/fonts/FontRoles.js +77 -0
- package/dist/shell/panel/fonts/FontRoles.js.map +1 -0
- package/dist/shell/panel/fonts/catalog.d.ts +37 -0
- package/dist/shell/panel/fonts/catalog.js +68 -0
- package/dist/shell/panel/fonts/catalog.js.map +1 -0
- package/dist/shell/panel/fonts/googleFontsCatalog.json +1 -0
- package/dist/shell/panel/index.d.ts +20 -0
- package/dist/shell/panel/index.js +34 -0
- package/dist/shell/panel/index.js.map +1 -0
- package/dist/shell/panel/languageModel.d.ts +5 -0
- package/dist/shell/panel/languageModel.js +7 -0
- package/dist/shell/panel/languageModel.js.map +1 -0
- package/dist/shell/panel/make.css +72 -0
- package/dist/shell/panel/makeModel.d.ts +32 -0
- package/dist/shell/panel/makeModel.js +84 -0
- package/dist/shell/panel/makeModel.js.map +1 -0
- package/dist/shell/panel/markdown.d.ts +46 -0
- package/dist/shell/panel/markdown.js +100 -0
- package/dist/shell/panel/markdown.js.map +1 -0
- package/dist/shell/panel/nav.d.ts +12 -0
- package/dist/shell/panel/nav.js +50 -0
- package/dist/shell/panel/nav.js.map +1 -0
- package/dist/shell/panel/panel.css +401 -0
- package/dist/shell/panel/panelMessages.d.ts +763 -0
- package/dist/shell/panel/panelMessages.js +767 -0
- package/dist/shell/panel/panelMessages.js.map +1 -0
- package/dist/shell/panel/plugins.css +59 -0
- package/dist/shell/panel/setupModel.d.ts +87 -0
- package/dist/shell/panel/setupModel.js +152 -0
- package/dist/shell/panel/setupModel.js.map +1 -0
- package/dist/shell/panel/site.d.ts +259 -0
- package/dist/shell/panel/site.js +25 -0
- package/dist/shell/panel/site.js.map +1 -0
- package/dist/shell/panel/strings.css +7 -0
- package/dist/shell/panel/themes.d.ts +10 -0
- package/dist/shell/panel/themes.js +8 -0
- package/dist/shell/panel/themes.js.map +1 -0
- package/dist/shell/profileModel.d.ts +3 -2
- package/dist/shell/profileModel.js +7 -5
- package/dist/shell/profileModel.js.map +1 -1
- package/dist/shell/store.css +230 -0
- package/dist/shell/storeMessages.d.ts +169 -0
- package/dist/shell/storeMessages.js +172 -0
- package/dist/shell/storeMessages.js.map +1 -0
- package/dist/shell/storeModel.d.ts +181 -0
- package/dist/shell/storeModel.js +133 -0
- package/dist/shell/storeModel.js.map +1 -0
- package/dist/shell/stringPacksModel.d.ts +44 -0
- package/dist/shell/stringPacksModel.js +94 -0
- package/dist/shell/stringPacksModel.js.map +1 -0
- package/dist/shell/updateModel.d.ts +2 -1
- package/dist/shell/updateModel.js +5 -4
- package/dist/shell/updateModel.js.map +1 -1
- package/dist/shell/windowControls.d.ts +4 -0
- package/dist/shell/windowControls.js +5 -0
- package/dist/shell/windowControls.js.map +1 -1
- package/i18n-config.schema.json +29 -0
- package/i18n-meta.schema.json +26 -0
- package/i18n.schema.json +42 -0
- package/icons.schema.json +646 -0
- package/languages.schema.json +23 -0
- package/locales/ar-x-fm.json +11 -0
- package/locales/ar.json +1281 -0
- package/locales/bg.json +1280 -0
- package/locales/bn.json +1280 -0
- package/locales/ca.json +1280 -0
- package/locales/cs.json +1280 -0
- package/locales/da.json +1280 -0
- package/locales/de.json +1280 -0
- package/locales/el.json +1280 -0
- package/locales/en-GB.json +27 -0
- package/locales/en.json +1280 -0
- package/locales/en.meta.json +51 -0
- package/locales/es.json +1280 -0
- package/locales/eu.json +1280 -0
- package/locales/fa.json +1281 -0
- package/locales/fi.json +1280 -0
- package/locales/fil.json +1280 -0
- package/locales/fr.json +1280 -0
- package/locales/ga.json +1280 -0
- package/locales/gl.json +1280 -0
- package/locales/gu.json +1280 -0
- package/locales/ha.json +1280 -0
- package/locales/he.json +1281 -0
- package/locales/hi.json +1280 -0
- package/locales/hr.json +1280 -0
- package/locales/hu.json +1279 -0
- package/locales/id.json +1280 -0
- package/locales/ig.json +1280 -0
- package/locales/it.json +1280 -0
- package/locales/ja.json +1280 -0
- package/locales/kn.json +1280 -0
- package/locales/ko.json +1280 -0
- package/locales/mr.json +1280 -0
- package/locales/ms.json +1280 -0
- package/locales/nb.json +1280 -0
- package/locales/nl.json +1280 -0
- package/locales/pl.json +1280 -0
- package/locales/pt.json +1280 -0
- package/locales/ro.json +1280 -0
- package/locales/ru.json +1280 -0
- package/locales/sk.json +1280 -0
- package/locales/sr.json +1280 -0
- package/locales/sv.json +1280 -0
- package/locales/ta.json +1280 -0
- package/locales/th.json +1280 -0
- package/locales/tr.json +1280 -0
- package/locales/uk.json +1280 -0
- package/locales/ur.json +1281 -0
- package/locales/vi.json +1280 -0
- package/locales/yo.json +1280 -0
- package/locales/zh-Hans.json +1280 -0
- package/locales/zh-Hant.json +1280 -0
- package/package.json +139 -5
- package/store-catalog.schema.json +65 -0
- package/theme.schema.json +4659 -0
- package/windows/installer.nsi +926 -0
- package/windows/languages/Basque.nsh +28 -0
- package/windows/languages/Catalan.nsh +28 -0
- package/windows/languages/Croatian.nsh +28 -0
- package/windows/languages/Czech.nsh +28 -0
- package/windows/languages/Danish.nsh +28 -0
- package/windows/languages/Finnish.nsh +28 -0
- package/windows/languages/Galician.nsh +28 -0
- package/windows/languages/Greek.nsh +28 -0
- package/windows/languages/Hungarian.nsh +28 -0
- package/windows/languages/Indonesian.nsh +28 -0
- package/windows/languages/Irish.nsh +28 -0
- package/windows/languages/Malay.nsh +28 -0
- package/windows/languages/Polish.nsh +28 -0
- package/windows/languages/Romanian.nsh +28 -0
- package/windows/languages/Serbian.nsh +28 -0
- package/windows/languages/Slovak.nsh +28 -0
- package/windows/languages/Thai.nsh +28 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
// Pure model of the app menu (the titlebar's "Settings and more": AppMenu.tsx), unit-tested under
|
|
2
|
+
// node: which rows an app gets (its `ShellSite.menu` groups, the built-in rows and what gates
|
|
3
|
+
// them), how the keyboard moves through them, the language list, the zoom steps and how a shortcut
|
|
4
|
+
// is written. No React, no Tauri.
|
|
5
|
+
//
|
|
6
|
+
// The menu's new words live in menuMessages.en.json (`wb.menu.*`) and are read through the
|
|
7
|
+
// framework i18n with that English as the fallback (`menuText`), so they work before the catalogs
|
|
8
|
+
// have them. Words the panel already has (section names, the mode question) are reused.
|
|
9
|
+
import { formatMessage } from "../../runtime/i18n.js";
|
|
10
|
+
import EN from './menuMessages.en.json' with { type: 'json' };
|
|
11
|
+
import { tx } from "./i18n.js";
|
|
12
|
+
/** The menu's English (`wb.menu.*`), for the catalogs. */
|
|
13
|
+
export const MENU_MESSAGES = EN;
|
|
14
|
+
/** A menu message in the active language; English from menuMessages.en.json until a catalog has it. */
|
|
15
|
+
export function menuText(name, params) {
|
|
16
|
+
const key = `wb.menu.${name}`;
|
|
17
|
+
return tx(key, params, '') || formatMessage(MENU_MESSAGES[key] ?? key, params ?? {});
|
|
18
|
+
}
|
|
19
|
+
// ---------------------------------------------------------------------------------------------
|
|
20
|
+
// What the app configures (`ShellSite.menu`)
|
|
21
|
+
/** The rows the frame brings. Each shows only when the app serves what it needs (`builtinAvailable`). */
|
|
22
|
+
export const MENU_BUILTINS = [
|
|
23
|
+
'new-tab', 'split-right', 'split-down', 'new-column',
|
|
24
|
+
'language', 'theme', 'mode',
|
|
25
|
+
'zoom',
|
|
26
|
+
'plugins', 'store', 'strings', 'workspaces',
|
|
27
|
+
'find', 'shortcuts', 'palette',
|
|
28
|
+
'developer', 'updates', 'safe-mode', 'report', 'about', 'settings',
|
|
29
|
+
];
|
|
30
|
+
/** The menu an app gets without saying anything: every built-in row it can serve. */
|
|
31
|
+
export const DEFAULT_MENU = [
|
|
32
|
+
['new-tab', 'split-right', 'split-down', 'new-column'],
|
|
33
|
+
['language', 'theme', 'mode'],
|
|
34
|
+
['zoom'],
|
|
35
|
+
['plugins', 'store', 'strings', 'workspaces'],
|
|
36
|
+
['find', 'shortcuts', 'palette'],
|
|
37
|
+
['developer', 'updates', 'safe-mode', 'report', 'about', 'settings'],
|
|
38
|
+
];
|
|
39
|
+
const entryId = (entry) => (typeof entry === 'string' ? entry : entry.id);
|
|
40
|
+
/** `groups` with the app's `items` put next to the row `anchor` (after it, or before). Without that row they form a last group. */
|
|
41
|
+
export function menuWith(groups, anchor, items, where = 'after') {
|
|
42
|
+
let placed = false;
|
|
43
|
+
const out = groups.map(group => {
|
|
44
|
+
const at = group.findIndex(entry => entryId(entry) === anchor);
|
|
45
|
+
if (at < 0 || placed)
|
|
46
|
+
return group;
|
|
47
|
+
placed = true;
|
|
48
|
+
const index = where === 'after' ? at + 1 : at;
|
|
49
|
+
return [...group.slice(0, index), ...items, ...group.slice(index)];
|
|
50
|
+
});
|
|
51
|
+
return placed ? out : [...out, items];
|
|
52
|
+
}
|
|
53
|
+
/** `groups` without the rows named. */
|
|
54
|
+
export function menuWithout(groups, ...ids) {
|
|
55
|
+
return groups.map(group => group.filter(entry => !ids.includes(entryId(entry))));
|
|
56
|
+
}
|
|
57
|
+
/** Whether the app can serve a built-in row: a row that would do nothing is never shown. */
|
|
58
|
+
export function builtinAvailable(id, env) {
|
|
59
|
+
switch (id) {
|
|
60
|
+
case 'new-column': return env.decks;
|
|
61
|
+
case 'language': return env.languages;
|
|
62
|
+
case 'theme': return env.themes;
|
|
63
|
+
case 'mode': return env.modes;
|
|
64
|
+
case 'zoom': return env.zoom;
|
|
65
|
+
case 'find': return env.find;
|
|
66
|
+
case 'safe-mode': return env.safeMode;
|
|
67
|
+
case 'store': return env.store;
|
|
68
|
+
case 'strings': return env.strings;
|
|
69
|
+
case 'workspaces': return env.workspaces;
|
|
70
|
+
case 'developer': return env.developer;
|
|
71
|
+
case 'updates': return env.updates;
|
|
72
|
+
default: return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const isBuiltin = (id) => MENU_BUILTINS.includes(id);
|
|
76
|
+
/**
|
|
77
|
+
* The entries the menu shows, group by group: built-in rows the app cannot serve and rows whose
|
|
78
|
+
* `when()` says no are left out, a row listed twice shows once, a group left empty goes (so no
|
|
79
|
+
* rule is ever doubled), and an unknown name is ignored.
|
|
80
|
+
*/
|
|
81
|
+
export function planMenu(groups, env) {
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
const out = [];
|
|
84
|
+
for (const group of groups) {
|
|
85
|
+
const kept = [];
|
|
86
|
+
for (const entry of group) {
|
|
87
|
+
const id = entryId(entry);
|
|
88
|
+
if (seen.has(id))
|
|
89
|
+
continue;
|
|
90
|
+
if (typeof entry === 'string') {
|
|
91
|
+
if (!isBuiltin(entry) || !builtinAvailable(entry, env))
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
else if (isBuiltin(id) || (entry.when && !entry.when())) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
seen.add(id);
|
|
98
|
+
kept.push(entry);
|
|
99
|
+
}
|
|
100
|
+
if (kept.length)
|
|
101
|
+
out.push(kept);
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
/** Groups of rows as one list with a rule between two groups. */
|
|
106
|
+
export function joinGroups(groups) {
|
|
107
|
+
const out = [];
|
|
108
|
+
for (const group of groups) {
|
|
109
|
+
if (!group.length)
|
|
110
|
+
continue;
|
|
111
|
+
if (out.length)
|
|
112
|
+
out.push({ kind: 'separator' });
|
|
113
|
+
out.push(...group);
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
/** The app's own entries as rows (`submenu` rows are looked up again when they open). */
|
|
118
|
+
export function specRows(specs) {
|
|
119
|
+
const out = [];
|
|
120
|
+
for (const spec of specs) {
|
|
121
|
+
if (spec.when && !spec.when())
|
|
122
|
+
continue;
|
|
123
|
+
if (spec.separated && out.length)
|
|
124
|
+
out.push({ kind: 'separator' });
|
|
125
|
+
const checked = spec.checked?.();
|
|
126
|
+
out.push({
|
|
127
|
+
kind: 'item', id: spec.id, label: spec.label(), icon: spec.icon, shortcut: spec.shortcut, hint: spec.hint?.(),
|
|
128
|
+
check: checked === undefined ? undefined : 'checkbox', checked, submenu: !!spec.submenu, keepOpen: spec.keepOpen, run: spec.run,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
/** The app's entry with this id, anywhere in its groups or their submenus. */
|
|
134
|
+
export function findSpec(groups, id) {
|
|
135
|
+
const walk = (specs, depth) => {
|
|
136
|
+
for (const spec of specs) {
|
|
137
|
+
if (spec.id === id)
|
|
138
|
+
return spec;
|
|
139
|
+
const inner = depth < 3 && spec.submenu ? walk(spec.submenu(), depth + 1) : null;
|
|
140
|
+
if (inner)
|
|
141
|
+
return inner;
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
};
|
|
145
|
+
return walk(groups.flat().filter((entry) => typeof entry !== 'string'), 0);
|
|
146
|
+
}
|
|
147
|
+
// ---------------------------------------------------------------------------------------------
|
|
148
|
+
// Keyboard
|
|
149
|
+
/** Arrow keys, Home and End over `count` stops; wraps around. -1 (nothing focused) enters at an end. */
|
|
150
|
+
export function moveStop(index, key, count) {
|
|
151
|
+
if (count <= 0)
|
|
152
|
+
return -1;
|
|
153
|
+
if (key === 'Home')
|
|
154
|
+
return 0;
|
|
155
|
+
if (key === 'End')
|
|
156
|
+
return count - 1;
|
|
157
|
+
if (key === 'ArrowDown')
|
|
158
|
+
return index < 0 ? 0 : (index + 1) % count;
|
|
159
|
+
if (key === 'ArrowUp')
|
|
160
|
+
return index < 0 ? count - 1 : (index - 1 + count) % count;
|
|
161
|
+
return index;
|
|
162
|
+
}
|
|
163
|
+
const fold = (text) => text.normalize('NFKD').replace(/\p{M}/gu, '').toLocaleLowerCase();
|
|
164
|
+
/**
|
|
165
|
+
* Type-ahead: the next stop after `from` whose label starts with what was typed (accents and case
|
|
166
|
+
* ignored). One letter typed again cycles through the labels that start with it. -1: none.
|
|
167
|
+
*/
|
|
168
|
+
export function typeahead(labels, from, typed) {
|
|
169
|
+
const text = fold(typed);
|
|
170
|
+
if (!text || !labels.length)
|
|
171
|
+
return -1;
|
|
172
|
+
const chars = [...text];
|
|
173
|
+
const repeat = chars.length > 1 && chars.every(char => char === chars[0]);
|
|
174
|
+
const needle = repeat ? chars[0] : text;
|
|
175
|
+
// While a word is being typed the focused row may keep matching; a repeated letter moves on.
|
|
176
|
+
const start = chars.length > 1 && !repeat ? Math.max(0, from) : from + 1;
|
|
177
|
+
for (let step = 0; step < labels.length; step += 1) {
|
|
178
|
+
const index = (start + step + labels.length) % labels.length;
|
|
179
|
+
if (fold(labels[index]).startsWith(needle))
|
|
180
|
+
return index;
|
|
181
|
+
}
|
|
182
|
+
return -1;
|
|
183
|
+
}
|
|
184
|
+
/** The keys that open and close a submenu: they follow the reading direction. */
|
|
185
|
+
export function submenuKeys(rtl) {
|
|
186
|
+
return rtl ? { open: 'ArrowLeft', close: 'ArrowRight' } : { open: 'ArrowRight', close: 'ArrowLeft' };
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* The left edge of a submenu `width` wide beside its menu (`parent`), in a window `viewport` wide.
|
|
190
|
+
* The menu hangs at one edge of the window (under its button at the end, under the logo at the
|
|
191
|
+
* start): the submenu opens toward the middle, else on the other side, else over the menu, and
|
|
192
|
+
* always stays `edge` pixels inside the window.
|
|
193
|
+
*/
|
|
194
|
+
export function submenuLeft(parent, width, viewport, edge = 8) {
|
|
195
|
+
const overlap = 3;
|
|
196
|
+
const before = parent.left - width + overlap;
|
|
197
|
+
const after = parent.right - overlap;
|
|
198
|
+
const fits = (x) => x >= edge && x + width <= viewport - edge;
|
|
199
|
+
const first = (parent.left + parent.right) / 2 > viewport / 2 ? before : after;
|
|
200
|
+
const second = first === before ? after : before;
|
|
201
|
+
if (fits(first))
|
|
202
|
+
return first;
|
|
203
|
+
if (fits(second))
|
|
204
|
+
return second;
|
|
205
|
+
return Math.max(edge, Math.min(first, viewport - width - edge));
|
|
206
|
+
}
|
|
207
|
+
/** A shortcut as the platform writes it: `Ctrl+Shift+T` on Windows and Linux, `⇧⌘T` on macOS. */
|
|
208
|
+
export function shortcutText(shortcut, mac) {
|
|
209
|
+
const parts = shortcut.split('+').map(part => part.trim()).filter(Boolean);
|
|
210
|
+
if (!mac)
|
|
211
|
+
return parts.join('+');
|
|
212
|
+
const symbols = { ctrl: '⌘', cmd: '⌘', shift: '⇧', alt: '⌥' };
|
|
213
|
+
const order = ['alt', 'shift', 'ctrl', 'cmd'];
|
|
214
|
+
const mods = parts.filter(part => part.toLowerCase() in symbols).sort((a, b) => order.indexOf(a.toLowerCase()) - order.indexOf(b.toLowerCase()));
|
|
215
|
+
const keys = parts.filter(part => !(part.toLowerCase() in symbols));
|
|
216
|
+
return `${mods.map(part => symbols[part.toLowerCase()]).join('')}${keys.join('')}`;
|
|
217
|
+
}
|
|
218
|
+
// ---------------------------------------------------------------------------------------------
|
|
219
|
+
// Language
|
|
220
|
+
/**
|
|
221
|
+
* The Language submenu: follow the site, follow the system, then the supported languages by their
|
|
222
|
+
* own names (the one chosen is checked; a community language in use is listed too, so the check is
|
|
223
|
+
* never missing), then the way to the full list in Settings.
|
|
224
|
+
*/
|
|
225
|
+
export function languageRows(list, state, words) {
|
|
226
|
+
const named = (code) => (code ? list.find(language => language.code === code)?.name : undefined);
|
|
227
|
+
const automatic = [
|
|
228
|
+
{ kind: 'item', id: 'lang:site', label: words.site, check: 'radio', checked: state.preference === 'site', hint: state.preference === 'site' ? named(state.locale) : named(state.siteLang) },
|
|
229
|
+
{ kind: 'item', id: 'lang:system', label: words.system, check: 'radio', checked: state.preference === 'system', hint: state.preference === 'system' ? named(state.locale) : undefined },
|
|
230
|
+
];
|
|
231
|
+
const shown = list.filter(language => language.tier !== 'community' || language.code === state.preference);
|
|
232
|
+
const languages = shown.map(language => ({
|
|
233
|
+
kind: 'item', id: `lang:${language.code}`, label: language.name, check: 'radio', checked: state.preference === language.code,
|
|
234
|
+
hint: language.name === language.englishName ? undefined : language.englishName, lang: language.code, dir: language.dir,
|
|
235
|
+
}));
|
|
236
|
+
return joinGroups([automatic, languages, [{ kind: 'item', id: 'lang:more', label: words.more }]]);
|
|
237
|
+
}
|
|
238
|
+
/** The preference a Language row stands for (`lang:tr` → `tr`), or null for "More languages…". */
|
|
239
|
+
export function languageChoice(id) {
|
|
240
|
+
const code = id.startsWith('lang:') ? id.slice(5) : '';
|
|
241
|
+
return code && code !== 'more' ? code : null;
|
|
242
|
+
}
|
|
243
|
+
// ---------------------------------------------------------------------------------------------
|
|
244
|
+
// Zoom
|
|
245
|
+
/** Page zoom limits, as native code clamps them (waybetter-host `zoom.rs`). */
|
|
246
|
+
export const ZOOM_MIN = 0.25;
|
|
247
|
+
export const ZOOM_MAX = 5;
|
|
248
|
+
/** The steps − and + move through (a browser's). */
|
|
249
|
+
export const ZOOM_STEPS = [0.25, 0.33, 0.5, 0.67, 0.75, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5];
|
|
250
|
+
/** The next step up (`1`) or down (`-1`) from `factor`, or 100% (`0`). Stays inside the limits. */
|
|
251
|
+
export function zoomStep(factor, direction) {
|
|
252
|
+
if (direction === 0 || !Number.isFinite(factor))
|
|
253
|
+
return 1;
|
|
254
|
+
const near = 0.005;
|
|
255
|
+
if (direction > 0)
|
|
256
|
+
return ZOOM_STEPS.find(step => step > factor + near) ?? ZOOM_MAX;
|
|
257
|
+
return [...ZOOM_STEPS].reverse().find(step => step < factor - near) ?? ZOOM_MIN;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The Updates row for the updater's status. `asked`: the owner asked for a check in this menu;
|
|
261
|
+
* only then does a check that did not get through say so (the timer's own failures stay quiet),
|
|
262
|
+
* and it says it calmly: a short state, never the error text.
|
|
263
|
+
*/
|
|
264
|
+
export function updateRow(status, asked, version) {
|
|
265
|
+
const check = menuText('updateCheck');
|
|
266
|
+
const quiet = version || undefined;
|
|
267
|
+
switch (status.state) {
|
|
268
|
+
case 'ready': return { label: menuText('updateRestart'), hint: status.version || quiet, action: 'restart' };
|
|
269
|
+
case 'installing': return { label: check, hint: menuText('updateInstalling', { version: status.version }), action: 'wait' };
|
|
270
|
+
case 'downloading': return { label: check, hint: menuText('updateDownloading', { version: status.version }), action: 'wait' };
|
|
271
|
+
case 'checking': return { label: check, hint: menuText('updateChecking'), action: 'wait' };
|
|
272
|
+
case 'problem': return { label: tx('wb.update.problemLabel'), hint: quiet, action: 'open' };
|
|
273
|
+
case 'upToDate': return { label: check, hint: version ? menuText('updateUpToDateVersion', { version }) : menuText('updateUpToDate'), action: 'check' };
|
|
274
|
+
case 'error': return asked ? { label: check, hint: menuText('updateFailed'), title: menuText('updateFailedHint'), action: 'check' } : { label: check, hint: quiet, action: 'check' };
|
|
275
|
+
default: return { label: check, hint: quiet, action: 'check' };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// ---------------------------------------------------------------------------------------------
|
|
279
|
+
// Find in page
|
|
280
|
+
/**
|
|
281
|
+
* What the find bar says about a search: "3/17" (the active match of the total), the total alone
|
|
282
|
+
* while no match is active, "No matches" for none. `number` writes a number in the active language.
|
|
283
|
+
*/
|
|
284
|
+
export function findLabel(counts, number = String) {
|
|
285
|
+
if (counts.count <= 0)
|
|
286
|
+
return menuText('findNone');
|
|
287
|
+
if (counts.index < 0 || counts.index >= counts.count)
|
|
288
|
+
return menuText('findTotal', { count: counts.count });
|
|
289
|
+
return menuText('findCount', { index: number(counts.index + 1), count: number(counts.count) });
|
|
290
|
+
}
|
|
291
|
+
/** Whole percent of a factor (1.1 → 110). */
|
|
292
|
+
export const zoomPercent = (factor) => Math.round(factor * 100);
|
|
293
|
+
//# sourceMappingURL=menuModel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menuModel.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/menuModel.ts"],"names":[],"mappings":"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","sourcesContent":["// Pure model of the app menu (the titlebar's \"Settings and more\": AppMenu.tsx), unit-tested under\n// node: which rows an app gets (its `ShellSite.menu` groups, the built-in rows and what gates\n// them), how the keyboard moves through them, the language list, the zoom steps and how a shortcut\n// is written. No React, no Tauri.\n//\n// The menu's new words live in menuMessages.en.json (`wb.menu.*`) and are read through the\n// framework i18n with that English as the fallback (`menuText`), so they work before the catalogs\n// have them. Words the panel already has (section names, the mode question) are reused.\n\nimport { formatMessage } from '../../../runtime/src/i18n.ts';\nimport type { UpdateStatus } from '../updateModel.ts';\nimport EN from './menuMessages.en.json' with { type: 'json' };\nimport { tx, type Params } from './i18n.ts';\nimport type { IconName } from './icons.tsx';\n\n/** The menu's English (`wb.menu.*`), for the catalogs. */\nexport const MENU_MESSAGES: Readonly<Record<string, string>> = EN;\n\ntype MenuKey = keyof typeof EN;\n/** A menu message's name: its key without the `wb.menu.` prefix. */\nexport type MenuWord = MenuKey extends `wb.menu.${infer Name}` ? Name : never;\n\n/** A menu message in the active language; English from menuMessages.en.json until a catalog has it. */\nexport function menuText(name: MenuWord, params?: Params): string {\n const key = `wb.menu.${name}`;\n return tx(key, params, '') || formatMessage(MENU_MESSAGES[key] ?? key, params ?? {});\n}\n\n// ---------------------------------------------------------------------------------------------\n// What the app configures (`ShellSite.menu`)\n\n/** The rows the frame brings. Each shows only when the app serves what it needs (`builtinAvailable`). */\nexport const MENU_BUILTINS = [\n 'new-tab', 'split-right', 'split-down', 'new-column',\n 'language', 'theme', 'mode',\n 'zoom',\n 'plugins', 'store', 'strings', 'workspaces',\n 'find', 'shortcuts', 'palette',\n 'developer', 'updates', 'safe-mode', 'report', 'about', 'settings',\n] as const;\nexport type BuiltinMenuItem = typeof MENU_BUILTINS[number];\n\n/** A row of the app's own. */\nexport type MenuItemSpec = {\n /** Unique in the menu (never a built-in's name). */\n id: string;\n label(): string;\n icon?: IconName;\n /** Its keys, written like `Ctrl+Shift+D` (shown as the platform writes them; the app handles the keys). */\n shortcut?: string;\n /** Quiet text at the end of the row instead of a shortcut (a count, a version). */\n hint?(): string;\n /** Leave the row out while this is false. */\n when?(): boolean;\n /** A toggle: the row is a checkbox showing this state; `run` flips it. */\n checked?(): boolean;\n run?(): void | Promise<void>;\n /** A submenu instead of an action (its rows may have submenus of their own). */\n submenu?(): MenuItemSpec[];\n /** Starts a new group (a rule above this row) inside a submenu. */\n separated?: boolean;\n /** The menu stays open after `run` (a toggle someone may flip back). */\n keepOpen?: boolean;\n};\n\nexport type MenuEntry = BuiltinMenuItem | MenuItemSpec;\n/** Ordered groups; a rule is drawn between two groups. */\nexport type MenuGroups = ReadonlyArray<ReadonlyArray<MenuEntry>>;\n\n/** One language of the app (a row of its `languages.json`). */\nexport type MenuLanguage = { code: string; name: string; englishName: string; dir: 'ltr' | 'rtl'; tier: 'supported' | 'community' };\n\n/** The app's language state (frame/language.ts `createLanguage`), as the panel's picker takes it. */\nexport type MenuLanguages = {\n list: readonly MenuLanguage[];\n state(): { preference: string; siteLang: string | null; locale: string };\n subscribe(listener: () => void): () => void;\n set(preference: string): Promise<void>;\n};\n\n/** The app's modes (Basic / Advanced / Power User): the panel's `menuModes()` gives this. */\nexport type MenuModes = {\n list(): ReadonlyArray<{ id: string; label: string }>;\n /** The mode in use (null: none chosen yet). */\n current(): Promise<string | null>;\n /** How many of the owner's own changes choosing `to` would replace (0: nothing to ask). */\n changes(to: string): Promise<number>;\n /** Applies `to`, keeping the owner's own changes or not. */\n apply(to: string, keep: boolean): Promise<void>;\n /** How the features relate to the mode in use (omit: the menu never says \"custom\"). */\n status?(): Promise<MenuModeStatus>;\n /** Applies the mode in use again as it is now: exactly what `status()` listed. */\n reapply?(): Promise<void>;\n /** The \"new features\" note was looked at; it is not shown again. */\n seen?(): Promise<void>;\n};\n\n/**\n * A mode is a starting point. `custom`: the features are no longer what the mode starts from;\n * `on` / `off`: the names of what applying it again would turn on and off; `added`: how many of\n * those the mode gained in an update since it was applied.\n */\nexport type MenuModeStatus = { custom: boolean; on: string[]; off: string[]; added: number };\n\n/** Lines an app adds to the \"Report a problem\" summary (reportModel.ts): ids only, never anything about the person. */\nexport type ReportDetails = ReadonlyArray<{ label: string; values: readonly string[] }>;\n\n/** `ShellSite.menu`: the app menu's rows and what the built-in ones need from the app. */\nexport type ShellMenu = {\n /** The rows, in order. A string is a built-in row, an object one of the app's. Default: `DEFAULT_MENU`. */\n groups?: MenuGroups;\n /** The Language submenu; omit for an app in one language. */\n languages?: MenuLanguages;\n /** The Mode submenu; omit for an app without modes. */\n modes?: MenuModes;\n /** The app's version, shown on the Updates row. */\n version?(): Promise<string>;\n /**\n * \"Report a problem\": the project's new-issue page (https; opened bare in the system browser, the\n * summary is never put in the URL) and lines the app adds to the summary (a fixed English label\n * and ids: what paused itself, which areas are on). Without `issueUrl` the dialog still shows and\n * copies the summary; its button is off and says there is no public page yet.\n */\n report?: { issueUrl?: string; details?(): ReportDetails | Promise<ReportDetails> };\n /** Opens the app's shortcuts sheet (\"Keyboard shortcuts…\"); without one the row opens the command palette. */\n shortcuts?(): void;\n};\n\n/** The menu an app gets without saying anything: every built-in row it can serve. */\nexport const DEFAULT_MENU: MenuGroups = [\n ['new-tab', 'split-right', 'split-down', 'new-column'],\n ['language', 'theme', 'mode'],\n ['zoom'],\n ['plugins', 'store', 'strings', 'workspaces'],\n ['find', 'shortcuts', 'palette'],\n ['developer', 'updates', 'safe-mode', 'report', 'about', 'settings'],\n];\n\nconst entryId = (entry: MenuEntry) => (typeof entry === 'string' ? entry : entry.id);\n\n/** `groups` with the app's `items` put next to the row `anchor` (after it, or before). Without that row they form a last group. */\nexport function menuWith(groups: MenuGroups, anchor: string, items: readonly MenuEntry[], where: 'after' | 'before' = 'after'): MenuGroups {\n let placed = false;\n const out = groups.map(group => {\n const at = group.findIndex(entry => entryId(entry) === anchor);\n if (at < 0 || placed) return group;\n placed = true;\n const index = where === 'after' ? at + 1 : at;\n return [...group.slice(0, index), ...items, ...group.slice(index)];\n });\n return placed ? out : [...out, items];\n}\n\n/** `groups` without the rows named. */\nexport function menuWithout(groups: MenuGroups, ...ids: string[]): MenuGroups {\n return groups.map(group => group.filter(entry => !ids.includes(entryId(entry))));\n}\n\n/** What the app serves, as far as the built-in rows care. */\nexport type MenuEnv = {\n /** Decks of site columns (`site.deck`). */\n decks: boolean;\n /** `menu.languages`. */\n languages: boolean;\n /** `site.themes`. */\n themes: boolean;\n /** `menu.modes` with at least one mode. */\n modes: boolean;\n /** `features`: native page zoom (`tab_zoom`), find in page (`tab_find`), the Store, workspaces, developer mode, the updater. */\n zoom: boolean;\n find: boolean;\n /** `features.safeMode`: safe mode for one run (`safe_mode_get/set`, the host's own). */\n safeMode: boolean;\n store: boolean;\n /** `features.strings`: the panel has the Languages section (string packs). */\n strings: boolean;\n workspaces: boolean;\n developer: boolean;\n updates: boolean;\n};\n\n/** Whether the app can serve a built-in row: a row that would do nothing is never shown. */\nexport function builtinAvailable(id: BuiltinMenuItem, env: MenuEnv): boolean {\n switch (id) {\n case 'new-column': return env.decks;\n case 'language': return env.languages;\n case 'theme': return env.themes;\n case 'mode': return env.modes;\n case 'zoom': return env.zoom;\n case 'find': return env.find;\n case 'safe-mode': return env.safeMode;\n case 'store': return env.store;\n case 'strings': return env.strings;\n case 'workspaces': return env.workspaces;\n case 'developer': return env.developer;\n case 'updates': return env.updates;\n default: return true;\n }\n}\n\nconst isBuiltin = (id: string): id is BuiltinMenuItem => (MENU_BUILTINS as readonly string[]).includes(id);\n\n/**\n * The entries the menu shows, group by group: built-in rows the app cannot serve and rows whose\n * `when()` says no are left out, a row listed twice shows once, a group left empty goes (so no\n * rule is ever doubled), and an unknown name is ignored.\n */\nexport function planMenu(groups: MenuGroups, env: MenuEnv): MenuEntry[][] {\n const seen = new Set<string>();\n const out: MenuEntry[][] = [];\n for (const group of groups) {\n const kept: MenuEntry[] = [];\n for (const entry of group) {\n const id = entryId(entry);\n if (seen.has(id)) continue;\n if (typeof entry === 'string') {\n if (!isBuiltin(entry) || !builtinAvailable(entry, env)) continue;\n } else if (isBuiltin(id) || (entry.when && !entry.when())) {\n continue;\n }\n seen.add(id);\n kept.push(entry);\n }\n if (kept.length) out.push(kept);\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Rows as the menu draws them\n\nexport type MenuItemRow = {\n kind: 'item';\n id: string;\n label: string;\n icon?: IconName;\n shortcut?: string;\n hint?: string;\n disabled?: boolean;\n /** A choice among its neighbours (radio) or a toggle (checkbox), with `checked`. */\n check?: 'radio' | 'checkbox';\n checked?: boolean;\n /** Opens a submenu (its rows come from the menu, by this row's id). */\n submenu?: boolean;\n keepOpen?: boolean;\n /** The label's own language and direction (a language's native name). */\n lang?: string;\n dir?: 'ltr' | 'rtl';\n /** The row's tooltip (a plain sentence that does not fit the row). */\n title?: string;\n /** A theme's colors, drawn as three dots (`ThemeAdapter.dots`). */\n swatch?: { page: string; bg: string; border: string; text: string; accent: string };\n run?(): unknown;\n};\n\nexport type MenuRow =\n | MenuItemRow\n | { kind: 'separator' }\n /** Words that are not a choice: a question above its answers, an empty list, an error. */\n | { kind: 'note'; id: string; title: string; text?: string; tone?: 'error' }\n /** The zoom row: − 100% + and a reset, in one line. */\n | { kind: 'zoom'; id: 'zoom' };\n\n/** Groups of rows as one list with a rule between two groups. */\nexport function joinGroups(groups: ReadonlyArray<readonly MenuRow[]>): MenuRow[] {\n const out: MenuRow[] = [];\n for (const group of groups) {\n if (!group.length) continue;\n if (out.length) out.push({ kind: 'separator' });\n out.push(...group);\n }\n return out;\n}\n\n/** The app's own entries as rows (`submenu` rows are looked up again when they open). */\nexport function specRows(specs: readonly MenuItemSpec[]): MenuRow[] {\n const out: MenuRow[] = [];\n for (const spec of specs) {\n if (spec.when && !spec.when()) continue;\n if (spec.separated && out.length) out.push({ kind: 'separator' });\n const checked = spec.checked?.();\n out.push({\n kind: 'item', id: spec.id, label: spec.label(), icon: spec.icon, shortcut: spec.shortcut, hint: spec.hint?.(),\n check: checked === undefined ? undefined : 'checkbox', checked, submenu: !!spec.submenu, keepOpen: spec.keepOpen, run: spec.run,\n });\n }\n return out;\n}\n\n/** The app's entry with this id, anywhere in its groups or their submenus. */\nexport function findSpec(groups: MenuGroups, id: string): MenuItemSpec | null {\n const walk = (specs: readonly MenuItemSpec[], depth: number): MenuItemSpec | null => {\n for (const spec of specs) {\n if (spec.id === id) return spec;\n const inner = depth < 3 && spec.submenu ? walk(spec.submenu(), depth + 1) : null;\n if (inner) return inner;\n }\n return null;\n };\n return walk(groups.flat().filter((entry): entry is MenuItemSpec => typeof entry !== 'string'), 0);\n}\n\n// ---------------------------------------------------------------------------------------------\n// Keyboard\n\n/** Arrow keys, Home and End over `count` stops; wraps around. -1 (nothing focused) enters at an end. */\nexport function moveStop(index: number, key: string, count: number): number {\n if (count <= 0) return -1;\n if (key === 'Home') return 0;\n if (key === 'End') return count - 1;\n if (key === 'ArrowDown') return index < 0 ? 0 : (index + 1) % count;\n if (key === 'ArrowUp') return index < 0 ? count - 1 : (index - 1 + count) % count;\n return index;\n}\n\nconst fold = (text: string) => text.normalize('NFKD').replace(/\\p{M}/gu, '').toLocaleLowerCase();\n\n/**\n * Type-ahead: the next stop after `from` whose label starts with what was typed (accents and case\n * ignored). One letter typed again cycles through the labels that start with it. -1: none.\n */\nexport function typeahead(labels: readonly string[], from: number, typed: string): number {\n const text = fold(typed);\n if (!text || !labels.length) return -1;\n const chars = [...text];\n const repeat = chars.length > 1 && chars.every(char => char === chars[0]);\n const needle = repeat ? chars[0]! : text;\n // While a word is being typed the focused row may keep matching; a repeated letter moves on.\n const start = chars.length > 1 && !repeat ? Math.max(0, from) : from + 1;\n for (let step = 0; step < labels.length; step += 1) {\n const index = (start + step + labels.length) % labels.length;\n if (fold(labels[index]!).startsWith(needle)) return index;\n }\n return -1;\n}\n\n/** The keys that open and close a submenu: they follow the reading direction. */\nexport function submenuKeys(rtl: boolean): { open: string; close: string } {\n return rtl ? { open: 'ArrowLeft', close: 'ArrowRight' } : { open: 'ArrowRight', close: 'ArrowLeft' };\n}\n\n/**\n * The left edge of a submenu `width` wide beside its menu (`parent`), in a window `viewport` wide.\n * The menu hangs at one edge of the window (under its button at the end, under the logo at the\n * start): the submenu opens toward the middle, else on the other side, else over the menu, and\n * always stays `edge` pixels inside the window.\n */\nexport function submenuLeft(parent: { left: number; right: number }, width: number, viewport: number, edge = 8): number {\n const overlap = 3;\n const before = parent.left - width + overlap;\n const after = parent.right - overlap;\n const fits = (x: number) => x >= edge && x + width <= viewport - edge;\n const first = (parent.left + parent.right) / 2 > viewport / 2 ? before : after;\n const second = first === before ? after : before;\n if (fits(first)) return first;\n if (fits(second)) return second;\n return Math.max(edge, Math.min(first, viewport - width - edge));\n}\n\n/** A shortcut as the platform writes it: `Ctrl+Shift+T` on Windows and Linux, `⇧⌘T` on macOS. */\nexport function shortcutText(shortcut: string, mac: boolean): string {\n const parts = shortcut.split('+').map(part => part.trim()).filter(Boolean);\n if (!mac) return parts.join('+');\n const symbols: Record<string, string> = { ctrl: '⌘', cmd: '⌘', shift: '⇧', alt: '⌥' };\n const order = ['alt', 'shift', 'ctrl', 'cmd'];\n const mods = parts.filter(part => part.toLowerCase() in symbols).sort((a, b) => order.indexOf(a.toLowerCase()) - order.indexOf(b.toLowerCase()));\n const keys = parts.filter(part => !(part.toLowerCase() in symbols));\n return `${mods.map(part => symbols[part.toLowerCase()]).join('')}${keys.join('')}`;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Language\n\n/**\n * The Language submenu: follow the site, follow the system, then the supported languages by their\n * own names (the one chosen is checked; a community language in use is listed too, so the check is\n * never missing), then the way to the full list in Settings.\n */\nexport function languageRows(\n list: readonly MenuLanguage[],\n state: { preference: string; siteLang: string | null; locale: string },\n words: { site: string; system: string; more: string },\n): MenuRow[] {\n const named = (code: string | null) => (code ? list.find(language => language.code === code)?.name : undefined);\n const automatic: MenuRow[] = [\n { kind: 'item', id: 'lang:site', label: words.site, check: 'radio', checked: state.preference === 'site', hint: state.preference === 'site' ? named(state.locale) : named(state.siteLang) },\n { kind: 'item', id: 'lang:system', label: words.system, check: 'radio', checked: state.preference === 'system', hint: state.preference === 'system' ? named(state.locale) : undefined },\n ];\n const shown = list.filter(language => language.tier !== 'community' || language.code === state.preference);\n const languages: MenuRow[] = shown.map(language => ({\n kind: 'item', id: `lang:${language.code}`, label: language.name, check: 'radio', checked: state.preference === language.code,\n hint: language.name === language.englishName ? undefined : language.englishName, lang: language.code, dir: language.dir,\n }));\n return joinGroups([automatic, languages, [{ kind: 'item', id: 'lang:more', label: words.more }]]);\n}\n\n/** The preference a Language row stands for (`lang:tr` → `tr`), or null for \"More languages…\". */\nexport function languageChoice(id: string): string | null {\n const code = id.startsWith('lang:') ? id.slice(5) : '';\n return code && code !== 'more' ? code : null;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Zoom\n\n/** Page zoom limits, as native code clamps them (waybetter-host `zoom.rs`). */\nexport const ZOOM_MIN = 0.25;\nexport const ZOOM_MAX = 5;\n/** The steps − and + move through (a browser's). */\nexport const ZOOM_STEPS = [0.25, 0.33, 0.5, 0.67, 0.75, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5] as const;\n\n/** The next step up (`1`) or down (`-1`) from `factor`, or 100% (`0`). Stays inside the limits. */\nexport function zoomStep(factor: number, direction: 1 | -1 | 0): number {\n if (direction === 0 || !Number.isFinite(factor)) return 1;\n const near = 0.005;\n if (direction > 0) return ZOOM_STEPS.find(step => step > factor + near) ?? ZOOM_MAX;\n return [...ZOOM_STEPS].reverse().find(step => step < factor - near) ?? ZOOM_MIN;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Updates\n\n/** The Updates row: what it says and what choosing it does. */\nexport type UpdateRow = {\n label: string;\n /** Quiet text at the end of the row: the state, or the version while nothing is happening. */\n hint?: string;\n /** A plain sentence for the row's tooltip (why a check did not get through). */\n title?: string;\n /** `check`: ask the updater now. `restart`: install the downloaded update. `open`: the Updates section. `wait`: nothing, a step is running. */\n action: 'check' | 'restart' | 'open' | 'wait';\n};\n\n/**\n * The Updates row for the updater's status. `asked`: the owner asked for a check in this menu;\n * only then does a check that did not get through say so (the timer's own failures stay quiet),\n * and it says it calmly: a short state, never the error text.\n */\nexport function updateRow(status: UpdateStatus, asked: boolean, version: string): UpdateRow {\n const check = menuText('updateCheck');\n const quiet = version || undefined;\n switch (status.state) {\n case 'ready': return { label: menuText('updateRestart'), hint: status.version || quiet, action: 'restart' };\n case 'installing': return { label: check, hint: menuText('updateInstalling', { version: status.version }), action: 'wait' };\n case 'downloading': return { label: check, hint: menuText('updateDownloading', { version: status.version }), action: 'wait' };\n case 'checking': return { label: check, hint: menuText('updateChecking'), action: 'wait' };\n case 'problem': return { label: tx('wb.update.problemLabel'), hint: quiet, action: 'open' };\n case 'upToDate': return { label: check, hint: version ? menuText('updateUpToDateVersion', { version }) : menuText('updateUpToDate'), action: 'check' };\n case 'error': return asked ? { label: check, hint: menuText('updateFailed'), title: menuText('updateFailedHint'), action: 'check' } : { label: check, hint: quiet, action: 'check' };\n default: return { label: check, hint: quiet, action: 'check' };\n }\n}\n\n// ---------------------------------------------------------------------------------------------\n// Find in page\n\n/**\n * What the find bar says about a search: \"3/17\" (the active match of the total), the total alone\n * while no match is active, \"No matches\" for none. `number` writes a number in the active language.\n */\nexport function findLabel(counts: { count: number; index: number }, number: (value: number) => string = String): string {\n if (counts.count <= 0) return menuText('findNone');\n if (counts.index < 0 || counts.index >= counts.count) return menuText('findTotal', { count: counts.count });\n return menuText('findCount', { index: number(counts.index + 1), count: number(counts.count) });\n}\n\n/** Whole percent of a factor (1.1 → 110). */\nexport const zoomPercent = (factor: number) => Math.round(factor * 100);\n"]}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { IconName } from './icons.tsx';
|
|
2
|
+
import type { PaletteSite } from './site.ts';
|
|
3
|
+
export { fuzzyScore, moveSelection } from '../palette.ts';
|
|
4
|
+
export type PaletteAction = {
|
|
5
|
+
type: 'focus-tab';
|
|
6
|
+
id: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'new-tab';
|
|
9
|
+
profile: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'panel';
|
|
12
|
+
section: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'open';
|
|
15
|
+
url: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'media';
|
|
18
|
+
}
|
|
19
|
+
/** Decks (navigation only): open a deck, make a new one, add or focus a column. */
|
|
20
|
+
| {
|
|
21
|
+
type: 'deck';
|
|
22
|
+
deckId?: string;
|
|
23
|
+
} | {
|
|
24
|
+
type: 'deck-new';
|
|
25
|
+
} | {
|
|
26
|
+
type: 'deck-add';
|
|
27
|
+
deckId: string;
|
|
28
|
+
} | {
|
|
29
|
+
type: 'deck-focus';
|
|
30
|
+
deckId: string;
|
|
31
|
+
columnId: string;
|
|
32
|
+
}
|
|
33
|
+
/** Replaces the palette query (a completion); never navigates. */
|
|
34
|
+
| {
|
|
35
|
+
type: 'complete';
|
|
36
|
+
text: string;
|
|
37
|
+
}
|
|
38
|
+
/** A plugin's command: the shell asks tab `tab` to run it in its page (`tab_run_command`). */
|
|
39
|
+
| {
|
|
40
|
+
type: 'plugin-command';
|
|
41
|
+
tab: string;
|
|
42
|
+
command: string;
|
|
43
|
+
}
|
|
44
|
+
/** Workspaces: restore one, or save the current layout under a name. */
|
|
45
|
+
| {
|
|
46
|
+
type: 'workspace';
|
|
47
|
+
id: string;
|
|
48
|
+
} | {
|
|
49
|
+
type: 'workspace-save';
|
|
50
|
+
}
|
|
51
|
+
/** Opens the app menu (the titlebar's "Settings and more"). */
|
|
52
|
+
| {
|
|
53
|
+
type: 'menu';
|
|
54
|
+
}
|
|
55
|
+
/** Opens the find bar of the tab in front. */
|
|
56
|
+
| {
|
|
57
|
+
type: 'find';
|
|
58
|
+
};
|
|
59
|
+
/** The frame's groups; the app's items are grouped under its product name, plugin commands under the plugin's. */
|
|
60
|
+
export type PaletteGroup = 'Tabs' | 'Deck' | 'Workspaces' | 'Profiles';
|
|
61
|
+
export type PaletteItem = {
|
|
62
|
+
id: string;
|
|
63
|
+
/** A fixed group, the site's group, or a plugin's name for its commands. */
|
|
64
|
+
group: PaletteGroup | (string & {});
|
|
65
|
+
label: string;
|
|
66
|
+
hint?: string;
|
|
67
|
+
keywords?: string;
|
|
68
|
+
/** The row's glyph (tabs show their favicon, profiles their avatar). */
|
|
69
|
+
icon?: IconName;
|
|
70
|
+
action: PaletteAction;
|
|
71
|
+
};
|
|
72
|
+
export type PaletteContext = {
|
|
73
|
+
/** `favicon` and `color` only decorate the list; matching ignores them. */
|
|
74
|
+
tabs: Array<{
|
|
75
|
+
id: string;
|
|
76
|
+
title: string;
|
|
77
|
+
url: string;
|
|
78
|
+
favicon?: string;
|
|
79
|
+
}>;
|
|
80
|
+
profiles: Array<{
|
|
81
|
+
id: string;
|
|
82
|
+
name: string;
|
|
83
|
+
color?: string;
|
|
84
|
+
}>;
|
|
85
|
+
activeProfile: string;
|
|
86
|
+
/** Decks and their columns (titles only); absent when the app has no decks. */
|
|
87
|
+
decks?: Array<{
|
|
88
|
+
id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
columns: Array<{
|
|
91
|
+
id: string;
|
|
92
|
+
title: string;
|
|
93
|
+
profile: string;
|
|
94
|
+
}>;
|
|
95
|
+
}>;
|
|
96
|
+
/** The deck tab in front, if any. */
|
|
97
|
+
activeDeck?: string;
|
|
98
|
+
/** Saved workspaces (names only) and the one opened last. */
|
|
99
|
+
workspaces?: Array<{
|
|
100
|
+
id: string;
|
|
101
|
+
name: string;
|
|
102
|
+
tabs: number;
|
|
103
|
+
isDefault?: boolean;
|
|
104
|
+
}>;
|
|
105
|
+
activeWorkspace?: string;
|
|
106
|
+
/** Plugin commands of the focused site tab, already named by plugin (`pluginCommandItems`). */
|
|
107
|
+
commands?: {
|
|
108
|
+
tab: string;
|
|
109
|
+
items: PluginCommandItem[];
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
/** What the palette knows about the app: its site items, its name and which frame features it has. */
|
|
113
|
+
export type PaletteSetup = {
|
|
114
|
+
site: PaletteSite;
|
|
115
|
+
product: string;
|
|
116
|
+
decks: boolean;
|
|
117
|
+
media: boolean;
|
|
118
|
+
workspaces?: boolean;
|
|
119
|
+
find?: boolean;
|
|
120
|
+
};
|
|
121
|
+
/** A plugin command as the palette lists it: the tab's report plus the plugin's display name. */
|
|
122
|
+
export type PluginCommandItem = {
|
|
123
|
+
id: string;
|
|
124
|
+
title: string;
|
|
125
|
+
keywords: string;
|
|
126
|
+
plugin: string;
|
|
127
|
+
};
|
|
128
|
+
/** Commands at most listed from one tab (the runtime and native code cap them too). */
|
|
129
|
+
export declare const MAX_PLUGIN_COMMANDS = 48;
|
|
130
|
+
/**
|
|
131
|
+
* Names each reported command (`<file>:<id>`) after its plugin (`@name` from the Plugins list);
|
|
132
|
+
* commands registered outside a plugin's start are listed under "Plugins". Bounded.
|
|
133
|
+
*/
|
|
134
|
+
export declare function pluginCommandItems(reported: ReadonlyArray<{
|
|
135
|
+
id: string;
|
|
136
|
+
title: string;
|
|
137
|
+
keywords?: string;
|
|
138
|
+
}>, pluginNames: Readonly<Record<string, string>>): PluginCommandItem[];
|
|
139
|
+
export declare function buildItems(context: PaletteContext, query: string, setup: PaletteSetup): PaletteItem[];
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Pure model for the command palette (no Tauri/DOM imports, so it is unit-tested under node).
|
|
2
|
+
// Every item is navigation only: tabs are focused, profiles open a tab, decks and workspaces open,
|
|
3
|
+
// the app's panel opens at a section, plugin commands run in their tab; the site adds its own
|
|
4
|
+
// pages and completions (`site.palette`). Nothing here performs an account action on the user's behalf.
|
|
5
|
+
import { rankItems } from "../palette.js";
|
|
6
|
+
import { t } from "./i18n.js";
|
|
7
|
+
import { menuText } from "./menuModel.js";
|
|
8
|
+
export { fuzzyScore, moveSelection } from "../palette.js";
|
|
9
|
+
/** Commands at most listed from one tab (the runtime and native code cap them too). */
|
|
10
|
+
export const MAX_PLUGIN_COMMANDS = 48;
|
|
11
|
+
/**
|
|
12
|
+
* Names each reported command (`<file>:<id>`) after its plugin (`@name` from the Plugins list);
|
|
13
|
+
* commands registered outside a plugin's start are listed under "Plugins". Bounded.
|
|
14
|
+
*/
|
|
15
|
+
export function pluginCommandItems(reported, pluginNames) {
|
|
16
|
+
const out = [];
|
|
17
|
+
for (const command of reported) {
|
|
18
|
+
if (out.length >= MAX_PLUGIN_COMMANDS)
|
|
19
|
+
break;
|
|
20
|
+
if (typeof command?.id !== 'string' || typeof command.title !== 'string')
|
|
21
|
+
continue;
|
|
22
|
+
const at = command.id.indexOf(':');
|
|
23
|
+
if (at <= 0)
|
|
24
|
+
continue;
|
|
25
|
+
const owner = command.id.slice(0, at);
|
|
26
|
+
const plugin = (owner !== '_' && pluginNames[owner]) || (owner === '_' ? t('wb.palette.plugins') : owner.replace(/\.plugin\.js$/, ''));
|
|
27
|
+
out.push({ id: command.id, title: command.title.slice(0, 80), keywords: (command.keywords ?? '').slice(0, 160), plugin });
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
/** The "Workspaces" group: switch to a saved workspace, save the current layout. */
|
|
32
|
+
function workspaceItems(context) {
|
|
33
|
+
const items = [];
|
|
34
|
+
for (const workspace of context.workspaces ?? []) {
|
|
35
|
+
items.push({
|
|
36
|
+
id: `ws:${workspace.id}`, group: 'Workspaces', label: t('wb.palette.switchTo', { name: workspace.name }),
|
|
37
|
+
hint: workspace.id === context.activeWorkspace ? t('wb.palette.active') : `${t('wb.ws.tabs', { count: workspace.tabs })}${workspace.isDefault ? ` · ${t('wb.palette.onStart')}` : ''}`,
|
|
38
|
+
keywords: 'workspace layout restore session switch', action: { type: 'workspace', id: workspace.id },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
items.push({ id: 'ws-save', group: 'Workspaces', label: t('wb.ws.save'), keywords: 'workspace layout save session tabs panes', action: { type: 'workspace-save' } });
|
|
42
|
+
return items;
|
|
43
|
+
}
|
|
44
|
+
/** The "Deck" group: open/switch decks, add a column, focus a column of the active deck. */
|
|
45
|
+
function deckItems(context) {
|
|
46
|
+
const decks = context.decks ?? [];
|
|
47
|
+
const items = [];
|
|
48
|
+
const active = decks.find(deck => deck.id === context.activeDeck);
|
|
49
|
+
if (!decks.length) {
|
|
50
|
+
items.push({ id: 'deck:open', group: 'Deck', label: t('wb.palette.openPower'), hint: 'Ctrl+Shift+D', keywords: 'deck tweetdeck columns power user', action: { type: 'deck' } });
|
|
51
|
+
return items;
|
|
52
|
+
}
|
|
53
|
+
for (const deck of decks) {
|
|
54
|
+
if (deck.id === active?.id)
|
|
55
|
+
continue;
|
|
56
|
+
items.push({ id: `deck:${deck.id}`, group: 'Deck', label: t('wb.palette.switchTo', { name: deck.name }), hint: t('wb.deck.columnCount', { count: deck.columns.length }), keywords: 'deck tweetdeck columns power user switch', action: { type: 'deck', deckId: deck.id } });
|
|
57
|
+
}
|
|
58
|
+
const target = active ?? decks[0];
|
|
59
|
+
items.push({ id: `deck-add:${target.id}`, group: 'Deck', label: t('wb.palette.addColumn'), hint: target.name, keywords: 'deck column new tweetdeck', action: { type: 'deck-add', deckId: target.id } });
|
|
60
|
+
if (active) {
|
|
61
|
+
active.columns.forEach((column, index) => {
|
|
62
|
+
items.push({ id: `deck-focus:${column.id}`, group: 'Deck', label: t('wb.palette.focusColumn', { name: column.title }), hint: index < 9 ? `Alt+${index + 1}` : undefined, keywords: 'column deck', action: { type: 'deck-focus', deckId: active.id, columnId: column.id } });
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
items.push({ id: 'deck-new', group: 'Deck', label: t('wb.palette.newDeck'), keywords: 'deck columns power user create', action: { type: 'deck-new' } });
|
|
66
|
+
return items;
|
|
67
|
+
}
|
|
68
|
+
export function buildItems(context, query, setup) {
|
|
69
|
+
const { site } = setup;
|
|
70
|
+
const items = [];
|
|
71
|
+
const text = query.trim();
|
|
72
|
+
const search = text ? site.search?.(text) ?? null : null;
|
|
73
|
+
if (search)
|
|
74
|
+
items.push(search);
|
|
75
|
+
for (const tab of context.tabs) {
|
|
76
|
+
items.push({ id: `tab:${tab.id}`, group: 'Tabs', label: tab.title || tab.url, hint: tab.url, keywords: tab.url, action: { type: 'focus-tab', id: tab.id } });
|
|
77
|
+
}
|
|
78
|
+
if (setup.decks)
|
|
79
|
+
items.push(...deckItems(context));
|
|
80
|
+
if (setup.workspaces !== false)
|
|
81
|
+
items.push(...workspaceItems(context));
|
|
82
|
+
for (const profile of context.profiles) {
|
|
83
|
+
items.push({ id: `profile:${profile.id}`, group: 'Profiles', label: t('wb.palette.newTabAs', { name: profile.name }), hint: profile.id === context.activeProfile ? t('wb.palette.active') : undefined, keywords: 'account switch', action: { type: 'new-tab', profile: profile.id } });
|
|
84
|
+
}
|
|
85
|
+
for (const section of site.sections) {
|
|
86
|
+
items.push({ id: `panel:${section.id}`, group: setup.product, label: section.label(), keywords: section.keywords, icon: section.icon, action: { type: 'panel', section: section.id } });
|
|
87
|
+
}
|
|
88
|
+
if (setup.media)
|
|
89
|
+
items.push({ id: 'media', group: setup.product, label: t('wb.palette.media'), hint: 'Ctrl+Shift+G', keywords: 'photos images screenshots attach paste media', icon: 'image', action: { type: 'media' } });
|
|
90
|
+
// Find in the page of the tab in front (the shell's find bar; nothing is sent anywhere).
|
|
91
|
+
if (setup.find !== false)
|
|
92
|
+
items.push({ id: 'find', group: setup.product, label: menuText('find'), hint: 'Ctrl+F', keywords: 'find search page text match', icon: 'search', action: { type: 'find' } });
|
|
93
|
+
// The app menu (the titlebar's "Settings and more"): language, theme, mode, zoom and the rest.
|
|
94
|
+
items.push({ id: 'app-menu', group: setup.product, label: menuText('label'), hint: 'Alt+F', keywords: 'menu more settings language theme mode zoom options preferences', icon: 'settings', action: { type: 'menu' } });
|
|
95
|
+
// Plugin commands, grouped under each plugin's name; they run in the focused site tab.
|
|
96
|
+
if (context.commands) {
|
|
97
|
+
const { tab } = context.commands;
|
|
98
|
+
// One heading per plugin: stable sort keeps each plugin's own order.
|
|
99
|
+
const sorted = context.commands.items.slice(0, MAX_PLUGIN_COMMANDS).sort((a, b) => a.plugin.localeCompare(b.plugin));
|
|
100
|
+
for (const command of sorted) {
|
|
101
|
+
items.push({ id: `cmd:${command.id}`, group: command.plugin, label: command.title, keywords: `${command.plugin} plugin ${command.keywords}`, icon: 'bolt', action: { type: 'plugin-command', tab, command: command.id } });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
items.push(...site.items?.() ?? []);
|
|
105
|
+
if (!text)
|
|
106
|
+
return items;
|
|
107
|
+
const completions = site.completions?.(query.replace(/^\s+/, '')) ?? [];
|
|
108
|
+
const scored = rankItems(items, text, item => item === search);
|
|
109
|
+
// The literal search stays available as the last resort.
|
|
110
|
+
return search ? [...completions, ...scored, search] : [...completions, ...scored];
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=paletteModel.js.map
|