waybetter 0.1.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -9
- 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 +148 -6
- 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,213 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Shared panel controls. One visual language for every setting: a row is label + hint on the left
|
|
3
|
+
// and one aligned control on the right (stacked under the label in a narrow split pane). Controls
|
|
4
|
+
// are small, keyboard-first and announce state with the matching ARIA role.
|
|
5
|
+
import { createContext, Fragment, useContext, useEffect, useId, useLayoutEffect, useRef, useState, } from 'react';
|
|
6
|
+
import { useT } from "../frame/hooks.js";
|
|
7
|
+
// ---------------------------------------------------------------------------------------------
|
|
8
|
+
// Search: rows hide themselves when they do not match the panel's settings search.
|
|
9
|
+
const SearchContext = createContext('');
|
|
10
|
+
export const SearchProvider = SearchContext.Provider;
|
|
11
|
+
export const useSettingsQuery = () => useContext(SearchContext);
|
|
12
|
+
/** Whether every word of the settings search is in one of `texts`. */
|
|
13
|
+
export const matchesQuery = (query, ...texts) => {
|
|
14
|
+
const words = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
15
|
+
const hay = texts.filter(Boolean).join(' ').toLowerCase();
|
|
16
|
+
return words.every(word => hay.includes(word));
|
|
17
|
+
};
|
|
18
|
+
/** Wraps text so the part matching the settings search is highlighted. */
|
|
19
|
+
function Mark({ text }) {
|
|
20
|
+
const query = useSettingsQuery().trim();
|
|
21
|
+
if (!query)
|
|
22
|
+
return _jsx(_Fragment, { children: text });
|
|
23
|
+
const word = query.split(/\s+/).find(w => text.toLowerCase().includes(w.toLowerCase()));
|
|
24
|
+
if (!word)
|
|
25
|
+
return _jsx(_Fragment, { children: text });
|
|
26
|
+
const at = text.toLowerCase().indexOf(word.toLowerCase());
|
|
27
|
+
return _jsxs(_Fragment, { children: [text.slice(0, at), _jsx("mark", { children: text.slice(at, at + word.length) }), text.slice(at + word.length)] });
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------------------------
|
|
30
|
+
// Layout
|
|
31
|
+
export function Section({ title, hint, action, children, id }) {
|
|
32
|
+
return _jsxs("section", { className: "bt-section", "aria-labelledby": id ? `${id}-h` : undefined, "data-section": title, children: [_jsxs("header", { className: "bt-section-head", children: [_jsxs("div", { children: [_jsx("h2", { id: id ? `${id}-h` : undefined, children: title }), hint && _jsx("p", { children: hint })] }), action && _jsx("div", { className: "bt-section-action", children: action })] }), _jsx("div", { className: "bt-card", children: children })] });
|
|
33
|
+
}
|
|
34
|
+
/** A setting: label and hint on the left, one control on the right. `wide` puts the control on its own line. */
|
|
35
|
+
export function Row({ label, hint, children, keywords, wide, badge }) {
|
|
36
|
+
const query = useSettingsQuery();
|
|
37
|
+
const id = useId();
|
|
38
|
+
if (query && !matchesQuery(query, label, typeof hint === 'string' ? hint : '', keywords))
|
|
39
|
+
return null;
|
|
40
|
+
return _jsxs("div", { className: `bt-row ${wide ? 'is-wide' : ''}`, role: "group", "aria-labelledby": id, children: [_jsxs("div", { className: "bt-row-copy", children: [_jsxs("div", { className: "bt-row-label", id: id, children: [_jsx(Mark, { text: label }), badge] }), hint && _jsx("div", { className: "bt-row-hint", children: typeof hint === 'string' ? _jsx(Mark, { text: hint }) : hint })] }), children && _jsx("div", { className: "bt-row-control", children: children })] });
|
|
41
|
+
}
|
|
42
|
+
export function Badge({ children, tone = 'plain' }) {
|
|
43
|
+
return _jsx("span", { className: `bt-badge is-${tone}`, children: children });
|
|
44
|
+
}
|
|
45
|
+
export function EmptyState({ icon, title, children, action }) {
|
|
46
|
+
return _jsxs("div", { className: "bt-empty", children: [icon && _jsx("div", { className: "bt-empty-icon", "aria-hidden": "true", children: icon }), _jsx("strong", { children: title }), children && _jsx("p", { children: children }), action && _jsx("div", { className: "bt-empty-action", children: action })] });
|
|
47
|
+
}
|
|
48
|
+
export function Button({ children, onClick, tone = 'plain', disabled, title, icon, size = 'md', type = 'button', label }) {
|
|
49
|
+
return _jsxs("button", { type: type, className: `bt-btn is-${tone} is-${size}`, disabled: disabled, title: title, "aria-label": label, onClick: onClick, children: [icon, children] });
|
|
50
|
+
}
|
|
51
|
+
// ---------------------------------------------------------------------------------------------
|
|
52
|
+
// Toggle
|
|
53
|
+
export function Toggle({ checked, onChange, label, disabled }) {
|
|
54
|
+
return _jsx("button", { type: "button", role: "switch", "aria-checked": checked, "aria-label": label, disabled: disabled, className: `bt-toggle ${checked ? 'is-on' : ''}`, onClick: () => onChange(!checked), children: _jsx("span", { className: "bt-toggle-knob" }) });
|
|
55
|
+
}
|
|
56
|
+
export function Segmented({ value, options, onChange, label, size = 'md' }) {
|
|
57
|
+
const ref = useRef(null);
|
|
58
|
+
const [thumb, setThumb] = useState({ opacity: 0 });
|
|
59
|
+
const index = options.findIndex(option => option.value === value);
|
|
60
|
+
useLayoutEffect(() => {
|
|
61
|
+
const root = ref.current;
|
|
62
|
+
const node = root?.querySelectorAll('[role="radio"]')[index];
|
|
63
|
+
if (!root || !node) {
|
|
64
|
+
setThumb({ opacity: 0 });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
setThumb({ opacity: 1, width: node.offsetWidth, transform: `translateX(${node.offsetLeft - 3}px)` });
|
|
68
|
+
}, [index, options.length]);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
const root = ref.current;
|
|
71
|
+
if (!root || typeof ResizeObserver === 'undefined')
|
|
72
|
+
return;
|
|
73
|
+
const observer = new ResizeObserver(() => {
|
|
74
|
+
const node = root.querySelectorAll('[role="radio"]')[index];
|
|
75
|
+
if (node)
|
|
76
|
+
setThumb({ opacity: 1, width: node.offsetWidth, transform: `translateX(${node.offsetLeft - 3}px)` });
|
|
77
|
+
});
|
|
78
|
+
observer.observe(root);
|
|
79
|
+
return () => observer.disconnect();
|
|
80
|
+
}, [index]);
|
|
81
|
+
const onKey = (event) => {
|
|
82
|
+
// Right-to-left layouts put the next option on the left.
|
|
83
|
+
const rtl = !!ref.current && getComputedStyle(ref.current).direction === 'rtl';
|
|
84
|
+
const forward = rtl ? 'ArrowLeft' : 'ArrowRight';
|
|
85
|
+
const back = rtl ? 'ArrowRight' : 'ArrowLeft';
|
|
86
|
+
const step = event.key === forward || event.key === 'ArrowDown' ? 1 : event.key === back || event.key === 'ArrowUp' ? -1 : 0;
|
|
87
|
+
if (!step)
|
|
88
|
+
return;
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
const next = options[(Math.max(index, 0) + step + options.length) % options.length];
|
|
91
|
+
onChange(next.value);
|
|
92
|
+
requestAnimationFrame(() => ref.current?.querySelector('[aria-checked="true"]')?.focus());
|
|
93
|
+
};
|
|
94
|
+
return _jsxs("div", { ref: ref, className: `bt-seg is-${size}`, role: "radiogroup", "aria-label": label, onKeyDown: onKey, children: [_jsx("span", { className: "bt-seg-thumb", style: thumb, "aria-hidden": "true" }), options.map((option, i) => _jsxs("button", { type: "button", role: "radio", "aria-checked": i === index, tabIndex: i === index || (index < 0 && i === 0) ? 0 : -1, title: option.hint, style: option.style, className: i === index ? 'is-on' : '', onClick: () => onChange(option.value), children: [option.icon, option.label] }, String(option.value)))] });
|
|
95
|
+
}
|
|
96
|
+
// ---------------------------------------------------------------------------------------------
|
|
97
|
+
// Select (listbox popover for longer lists)
|
|
98
|
+
export function Select({ value, options, onChange, label, placeholder: givenPlaceholder, width }) {
|
|
99
|
+
const t = useT();
|
|
100
|
+
const placeholder = givenPlaceholder ?? t('wb.ui.select.placeholder');
|
|
101
|
+
const [open, setOpen] = useState(false);
|
|
102
|
+
const [active, setActive] = useState(0);
|
|
103
|
+
const root = useRef(null);
|
|
104
|
+
const list = useRef(null);
|
|
105
|
+
const id = useId();
|
|
106
|
+
const current = options.find(option => option.value === value);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (!open)
|
|
109
|
+
return;
|
|
110
|
+
setActive(Math.max(0, options.findIndex(option => option.value === value)));
|
|
111
|
+
const close = (event) => { if (!root.current?.contains(event.target))
|
|
112
|
+
setOpen(false); };
|
|
113
|
+
document.addEventListener('pointerdown', close);
|
|
114
|
+
return () => document.removeEventListener('pointerdown', close);
|
|
115
|
+
}, [open]);
|
|
116
|
+
useEffect(() => { if (open)
|
|
117
|
+
list.current?.querySelectorAll('li[role="option"]')[active]?.scrollIntoView({ block: 'nearest' }); }, [active, open]);
|
|
118
|
+
const choose = (option) => { onChange(option.value); setOpen(false); root.current?.querySelector('button')?.focus(); };
|
|
119
|
+
const onKey = (event) => {
|
|
120
|
+
if (!open && ['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(event.key)) {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
setOpen(true);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (!open)
|
|
126
|
+
return;
|
|
127
|
+
if (event.key === 'Escape') {
|
|
128
|
+
event.preventDefault();
|
|
129
|
+
event.stopPropagation();
|
|
130
|
+
setOpen(false);
|
|
131
|
+
}
|
|
132
|
+
else if (event.key === 'ArrowDown') {
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
setActive(i => Math.min(options.length - 1, i + 1));
|
|
135
|
+
}
|
|
136
|
+
else if (event.key === 'ArrowUp') {
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
setActive(i => Math.max(0, i - 1));
|
|
139
|
+
}
|
|
140
|
+
else if (event.key === 'Home') {
|
|
141
|
+
event.preventDefault();
|
|
142
|
+
setActive(0);
|
|
143
|
+
}
|
|
144
|
+
else if (event.key === 'End') {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
setActive(options.length - 1);
|
|
147
|
+
}
|
|
148
|
+
else if (event.key === 'Enter' || event.key === ' ') {
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
const option = options[active];
|
|
151
|
+
if (option)
|
|
152
|
+
choose(option);
|
|
153
|
+
}
|
|
154
|
+
else if (event.key === 'Tab')
|
|
155
|
+
setOpen(false);
|
|
156
|
+
};
|
|
157
|
+
return _jsxs("div", { ref: root, className: `bt-select ${open ? 'is-open' : ''}`, style: width ? { width } : undefined, onKeyDown: onKey, children: [_jsxs("button", { type: "button", className: "bt-select-button", "aria-haspopup": "listbox", "aria-expanded": open, "aria-label": `${label}: ${current?.label ?? placeholder}`, "aria-controls": id, onClick: () => setOpen(!open), children: [_jsxs("span", { className: "bt-select-value", style: current?.style, children: [current?.icon, current?.label ?? placeholder] }), _jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", "aria-hidden": "true", children: _jsx("path", { d: "M3 4.5 6 7.5 9 4.5", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })] }), open && _jsx("ul", { ref: list, id: id, role: "listbox", "aria-label": label, className: "bt-select-list", "aria-activedescendant": `${id}-${active}`, children: options.map((option, i) => _jsxs(Fragment, { children: [option.group && option.group !== options[i - 1]?.group && _jsx("li", { role: "presentation", className: "bt-select-group", children: option.group }), _jsxs("li", { id: `${id}-${i}`, role: "option", "aria-selected": option.value === value, className: `${i === active ? 'is-active' : ''} ${option.value === value ? 'is-on' : ''}`, onPointerEnter: () => setActive(i), onClick: () => choose(option), children: [_jsxs("span", { className: "bt-select-opt", style: option.style, children: [option.icon, option.label] }), option.hint && _jsx("small", { children: option.hint }), option.value === value && _jsx("svg", { className: "bt-select-check", width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: _jsx("path", { d: "m3 7.5 2.5 2.5L11 4.5", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) })] })] }, String(option.value))) })] });
|
|
158
|
+
}
|
|
159
|
+
// ---------------------------------------------------------------------------------------------
|
|
160
|
+
// Slider
|
|
161
|
+
export function Slider({ value, min, max, step = 1, onChange, onCommit, label, format }) {
|
|
162
|
+
const pct = ((value - min) / (max - min)) * 100;
|
|
163
|
+
return _jsxs("div", { className: "bt-slider", children: [_jsx("input", { type: "range", min: min, max: max, step: step, value: value, "aria-label": label, "aria-valuetext": format(value), style: { '--pct': `${pct}%` }, onChange: event => onChange(Number(event.target.value)), onPointerUp: event => onCommit?.(Number(event.target.value)), onKeyUp: event => onCommit?.(Number(event.target.value)) }), _jsx("output", { children: format(value) })] });
|
|
164
|
+
}
|
|
165
|
+
// ---------------------------------------------------------------------------------------------
|
|
166
|
+
// Color: swatches, a custom picker and a hex field
|
|
167
|
+
export function ColorField({ value, swatches, onChange, autoLabel, label }) {
|
|
168
|
+
const t = useT();
|
|
169
|
+
const [draft, setDraft] = useState(value ?? '');
|
|
170
|
+
useEffect(() => setDraft(value ?? ''), [value]);
|
|
171
|
+
const custom = value && !swatches.includes(value);
|
|
172
|
+
const commit = (text) => {
|
|
173
|
+
const hex = text.trim().replace(/^([0-9a-f]{6})$/i, '#$1').toLowerCase();
|
|
174
|
+
if (/^#[0-9a-f]{6}$/.test(hex))
|
|
175
|
+
onChange(hex);
|
|
176
|
+
else
|
|
177
|
+
setDraft(value ?? '');
|
|
178
|
+
};
|
|
179
|
+
return _jsxs("div", { className: "bt-color", role: "radiogroup", "aria-label": label, children: [autoLabel && _jsx("button", { type: "button", role: "radio", "aria-checked": !value, className: `bt-swatch is-auto ${!value ? 'is-on' : ''}`, onClick: () => onChange(null), children: autoLabel }), swatches.map(color => _jsx("button", { type: "button", role: "radio", "aria-checked": value === color, "aria-label": color, title: color, className: `bt-swatch ${value === color ? 'is-on' : ''}`, style: { '--sw': color }, onClick: () => onChange(color) }, color)), _jsx("label", { className: `bt-swatch is-picker ${custom ? 'is-on' : ''}`, title: t('wb.ui.color.pick'), style: custom ? { '--sw': value } : undefined, children: _jsx("input", { type: "color", "aria-label": t('wb.ui.color.custom', { label }), value: value ?? '#1d9bf0', onChange: event => onChange(event.target.value.toLowerCase()) }) }), _jsx("input", { className: "bt-hex", "aria-label": t('wb.ui.color.hex', { label }), spellCheck: false, maxLength: 7, placeholder: "#rrggbb", value: draft, onChange: event => setDraft(event.target.value), onBlur: event => commit(event.target.value), onKeyDown: event => { if (event.key === 'Enter')
|
|
180
|
+
commit(event.target.value); } })] });
|
|
181
|
+
}
|
|
182
|
+
// ---------------------------------------------------------------------------------------------
|
|
183
|
+
// Text inputs
|
|
184
|
+
export function TextInput({ value, onChange, placeholder, label, type = 'text', width, onEnter, mono }) {
|
|
185
|
+
return _jsx("input", { className: `bt-input ${mono ? 'is-mono' : ''}`, type: type, "aria-label": label, placeholder: placeholder, value: value, style: width ? { width } : undefined, onChange: event => onChange(event.target.value), onKeyDown: event => { if (event.key === 'Enter')
|
|
186
|
+
onEnter?.(); } });
|
|
187
|
+
}
|
|
188
|
+
/** An input with its action button attached (Save, Add…). */
|
|
189
|
+
export function InputRow({ value, onChange, onSubmit, placeholder, label, button, disabled, mono }) {
|
|
190
|
+
return _jsxs("form", { className: "bt-inputrow", onSubmit: event => { event.preventDefault(); if (!disabled)
|
|
191
|
+
onSubmit(); }, children: [_jsx("input", { className: mono ? 'is-mono' : '', "aria-label": label, placeholder: placeholder, value: value, onChange: event => onChange(event.target.value) }), _jsx("button", { type: "submit", disabled: disabled, children: button })] });
|
|
192
|
+
}
|
|
193
|
+
export function SearchField({ value, onChange, placeholder, label }) {
|
|
194
|
+
const t = useT();
|
|
195
|
+
return _jsxs("label", { className: "bt-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", { type: "search", "aria-label": label, placeholder: placeholder, value: value, onChange: event => onChange(event.target.value), onKeyDown: event => { if (event.key === 'Escape' && value) {
|
|
196
|
+
event.stopPropagation();
|
|
197
|
+
onChange('');
|
|
198
|
+
} } }), value && _jsx("button", { type: "button", "aria-label": t('wb.ui.search.clear'), onClick: () => onChange(''), children: "\u00D7" })] });
|
|
199
|
+
}
|
|
200
|
+
// ---------------------------------------------------------------------------------------------
|
|
201
|
+
// Chips: removable list items (folders, keywords)
|
|
202
|
+
export function ChipList({ items, onRemove, render, title, empty, icon }) {
|
|
203
|
+
const t = useT();
|
|
204
|
+
if (!items.length)
|
|
205
|
+
return empty ? _jsx("p", { className: "bt-chips-empty", children: empty }) : null;
|
|
206
|
+
return _jsx("ul", { className: "bt-chips", children: items.map(item => _jsxs("li", { className: "bt-chip", title: title?.(item) ?? item, children: [icon, _jsx("span", { children: render ? render(item) : item }), _jsx("button", { type: "button", "aria-label": t('wb.ui.chip.remove', { item: render ? render(item) : item }), onClick: () => onRemove(item), children: _jsx("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: _jsx("path", { d: "m2.5 2.5 5 5m0-5-5 5", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round" }) }) })] }, item)) });
|
|
207
|
+
}
|
|
208
|
+
/** Number with − / + buttons. */
|
|
209
|
+
export function Stepper({ value, min, max, onChange, label, suffix }) {
|
|
210
|
+
const t = useT();
|
|
211
|
+
return _jsxs("div", { className: "bt-stepper", role: "group", "aria-label": label, children: [_jsx("button", { type: "button", "aria-label": t('wb.ui.stepper.decrease', { label }), disabled: value <= min, onClick: () => onChange(Math.max(min, value - 1)), children: "\u2212" }), _jsxs("output", { "aria-live": "polite", children: [value, suffix && _jsx("small", { children: suffix })] }), _jsx("button", { type: "button", "aria-label": t('wb.ui.stepper.increase', { label }), disabled: value >= max, onClick: () => onChange(Math.min(max, value + 1)), children: "+" })] });
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=controls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controls.js","sourceRoot":"","sources":["../../../../../../shell/src/panel/controls.tsx"],"names":[],"mappings":"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","sourcesContent":["// Shared panel controls. One visual language for every setting: a row is label + hint on the left\n// and one aligned control on the right (stacked under the label in a narrow split pane). Controls\n// are small, keyboard-first and announce state with the matching ARIA role.\nimport {\n createContext, Fragment, useContext, useEffect, useId, useLayoutEffect, useRef, useState,\n type CSSProperties, type KeyboardEvent, type ReactNode,\n} from 'react';\nimport { useT } from '../frame/hooks.ts';\n\n// ---------------------------------------------------------------------------------------------\n// Search: rows hide themselves when they do not match the panel's settings search.\n\nconst SearchContext = createContext('');\nexport const SearchProvider = SearchContext.Provider;\nexport const useSettingsQuery = () => useContext(SearchContext);\n/** Whether every word of the settings search is in one of `texts`. */\nexport const matchesQuery = (query: string, ...texts: Array<string | undefined>) => {\n const words = query.toLowerCase().split(/\\s+/).filter(Boolean);\n const hay = texts.filter(Boolean).join(' ').toLowerCase();\n return words.every(word => hay.includes(word));\n};\n\n/** Wraps text so the part matching the settings search is highlighted. */\nfunction Mark({ text }: { text: string }) {\n const query = useSettingsQuery().trim();\n if (!query) return <>{text}</>;\n const word = query.split(/\\s+/).find(w => text.toLowerCase().includes(w.toLowerCase()));\n if (!word) return <>{text}</>;\n const at = text.toLowerCase().indexOf(word.toLowerCase());\n return <>{text.slice(0, at)}<mark>{text.slice(at, at + word.length)}</mark>{text.slice(at + word.length)}</>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Layout\n\nexport function Section({ title, hint, action, children, id }: { title: string; hint?: ReactNode; action?: ReactNode; children: ReactNode; id?: string }) {\n return <section className=\"bt-section\" aria-labelledby={id ? `${id}-h` : undefined} data-section={title}>\n <header className=\"bt-section-head\">\n <div><h2 id={id ? `${id}-h` : undefined}>{title}</h2>{hint && <p>{hint}</p>}</div>\n {action && <div className=\"bt-section-action\">{action}</div>}\n </header>\n <div className=\"bt-card\">{children}</div>\n </section>;\n}\n\n/** A setting: label and hint on the left, one control on the right. `wide` puts the control on its own line. */\nexport function Row({ label, hint, children, keywords, wide, badge }: { label: string; hint?: ReactNode; children?: ReactNode; keywords?: string; wide?: boolean; badge?: ReactNode }) {\n const query = useSettingsQuery();\n const id = useId();\n if (query && !matchesQuery(query, label, typeof hint === 'string' ? hint : '', keywords)) return null;\n return <div className={`bt-row ${wide ? 'is-wide' : ''}`} role=\"group\" aria-labelledby={id}>\n <div className=\"bt-row-copy\">\n <div className=\"bt-row-label\" id={id}><Mark text={label}/>{badge}</div>\n {hint && <div className=\"bt-row-hint\">{typeof hint === 'string' ? <Mark text={hint}/> : hint}</div>}\n </div>\n {children && <div className=\"bt-row-control\">{children}</div>}\n </div>;\n}\n\nexport function Badge({ children, tone = 'plain' }: { children: ReactNode; tone?: 'plain' | 'accent' | 'warn' | 'ok' }) {\n return <span className={`bt-badge is-${tone}`}>{children}</span>;\n}\n\nexport function EmptyState({ icon, title, children, action }: { icon?: ReactNode; title: string; children?: ReactNode; action?: ReactNode }) {\n return <div className=\"bt-empty\">\n {icon && <div className=\"bt-empty-icon\" aria-hidden=\"true\">{icon}</div>}\n <strong>{title}</strong>\n {children && <p>{children}</p>}\n {action && <div className=\"bt-empty-action\">{action}</div>}\n </div>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Buttons\n\ntype ButtonProps = { children: ReactNode; onClick?: () => void; tone?: 'plain' | 'primary' | 'danger' | 'ghost'; disabled?: boolean; title?: string; icon?: ReactNode; size?: 'sm' | 'md'; type?: 'button' | 'submit'; label?: string };\nexport function Button({ children, onClick, tone = 'plain', disabled, title, icon, size = 'md', type = 'button', label }: ButtonProps) {\n return <button type={type} className={`bt-btn is-${tone} is-${size}`} disabled={disabled} title={title} aria-label={label} onClick={onClick}>{icon}{children}</button>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Toggle\n\nexport function Toggle({ checked, onChange, label, disabled }: { checked: boolean; onChange(next: boolean): void; label: string; disabled?: boolean }) {\n return <button type=\"button\" role=\"switch\" aria-checked={checked} aria-label={label} disabled={disabled} className={`bt-toggle ${checked ? 'is-on' : ''}`} onClick={() => onChange(!checked)}>\n <span className=\"bt-toggle-knob\"/>\n </button>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Segmented control (2-4 options)\n\n/** `group`: a Select shows a heading above the first option of each group (options of a group are consecutive). */\nexport type Option<T extends string | number> = { value: T; label: string; hint?: string; icon?: ReactNode; style?: CSSProperties; group?: string };\n\nexport function Segmented<T extends string | number>({ value, options, onChange, label, size = 'md' }: { value: T | null; options: Array<Option<T>>; onChange(next: T): void; label: string; size?: 'sm' | 'md' }) {\n const ref = useRef<HTMLDivElement>(null);\n const [thumb, setThumb] = useState<CSSProperties>({ opacity: 0 });\n const index = options.findIndex(option => option.value === value);\n useLayoutEffect(() => {\n const root = ref.current;\n const node = root?.querySelectorAll<HTMLElement>('[role=\"radio\"]')[index];\n if (!root || !node) { setThumb({ opacity: 0 }); return; }\n setThumb({ opacity: 1, width: node.offsetWidth, transform: `translateX(${node.offsetLeft - 3}px)` });\n }, [index, options.length]);\n useEffect(() => {\n const root = ref.current;\n if (!root || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => {\n const node = root.querySelectorAll<HTMLElement>('[role=\"radio\"]')[index];\n if (node) setThumb({ opacity: 1, width: node.offsetWidth, transform: `translateX(${node.offsetLeft - 3}px)` });\n });\n observer.observe(root);\n return () => observer.disconnect();\n }, [index]);\n const onKey = (event: KeyboardEvent) => {\n // Right-to-left layouts put the next option on the left.\n const rtl = !!ref.current && getComputedStyle(ref.current).direction === 'rtl';\n const forward = rtl ? 'ArrowLeft' : 'ArrowRight';\n const back = rtl ? 'ArrowRight' : 'ArrowLeft';\n const step = event.key === forward || event.key === 'ArrowDown' ? 1 : event.key === back || event.key === 'ArrowUp' ? -1 : 0;\n if (!step) return;\n event.preventDefault();\n const next = options[(Math.max(index, 0) + step + options.length) % options.length]!;\n onChange(next.value);\n requestAnimationFrame(() => ref.current?.querySelector<HTMLElement>('[aria-checked=\"true\"]')?.focus());\n };\n return <div ref={ref} className={`bt-seg is-${size}`} role=\"radiogroup\" aria-label={label} onKeyDown={onKey}>\n <span className=\"bt-seg-thumb\" style={thumb} aria-hidden=\"true\"/>\n {options.map((option, i) => <button key={String(option.value)} type=\"button\" role=\"radio\" aria-checked={i === index} tabIndex={i === index || (index < 0 && i === 0) ? 0 : -1}\n title={option.hint} style={option.style} className={i === index ? 'is-on' : ''} onClick={() => onChange(option.value)}>{option.icon}{option.label}</button>)}\n </div>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Select (listbox popover for longer lists)\n\nexport function Select<T extends string>({ value, options, onChange, label, placeholder: givenPlaceholder, width }: { value: T | null; options: Array<Option<T>>; onChange(next: T): void; label: string; placeholder?: string; width?: number }) {\n const t = useT();\n const placeholder = givenPlaceholder ?? t('wb.ui.select.placeholder');\n const [open, setOpen] = useState(false);\n const [active, setActive] = useState(0);\n const root = useRef<HTMLDivElement>(null);\n const list = useRef<HTMLUListElement>(null);\n const id = useId();\n const current = options.find(option => option.value === value);\n useEffect(() => {\n if (!open) return;\n setActive(Math.max(0, options.findIndex(option => option.value === value)));\n const close = (event: PointerEvent) => { if (!root.current?.contains(event.target as Node)) setOpen(false); };\n document.addEventListener('pointerdown', close);\n return () => document.removeEventListener('pointerdown', close);\n }, [open]);\n useEffect(() => { if (open) list.current?.querySelectorAll('li[role=\"option\"]')[active]?.scrollIntoView({ block: 'nearest' }); }, [active, open]);\n const choose = (option: Option<T>) => { onChange(option.value); setOpen(false); root.current?.querySelector<HTMLElement>('button')?.focus(); };\n const onKey = (event: KeyboardEvent) => {\n if (!open && ['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(event.key)) { event.preventDefault(); setOpen(true); return; }\n if (!open) return;\n if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); setOpen(false); }\n else if (event.key === 'ArrowDown') { event.preventDefault(); setActive(i => Math.min(options.length - 1, i + 1)); }\n else if (event.key === 'ArrowUp') { event.preventDefault(); setActive(i => Math.max(0, i - 1)); }\n else if (event.key === 'Home') { event.preventDefault(); setActive(0); }\n else if (event.key === 'End') { event.preventDefault(); setActive(options.length - 1); }\n else if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); const option = options[active]; if (option) choose(option); }\n else if (event.key === 'Tab') setOpen(false);\n };\n return <div ref={root} className={`bt-select ${open ? 'is-open' : ''}`} style={width ? { width } : undefined} onKeyDown={onKey}>\n <button type=\"button\" className=\"bt-select-button\" aria-haspopup=\"listbox\" aria-expanded={open} aria-label={`${label}: ${current?.label ?? placeholder}`} aria-controls={id} onClick={() => setOpen(!open)}>\n <span className=\"bt-select-value\" style={current?.style}>{current?.icon}{current?.label ?? placeholder}</span>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\"><path d=\"M3 4.5 6 7.5 9 4.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>\n </button>\n {open && <ul ref={list} id={id} role=\"listbox\" aria-label={label} className=\"bt-select-list\" aria-activedescendant={`${id}-${active}`}>\n {options.map((option, i) => <Fragment key={String(option.value)}>\n {option.group && option.group !== options[i - 1]?.group && <li role=\"presentation\" className=\"bt-select-group\">{option.group}</li>}\n <li id={`${id}-${i}`} role=\"option\" aria-selected={option.value === value}\n className={`${i === active ? 'is-active' : ''} ${option.value === value ? 'is-on' : ''}`} onPointerEnter={() => setActive(i)} onClick={() => choose(option)}>\n <span className=\"bt-select-opt\" style={option.style}>{option.icon}{option.label}</span>\n {option.hint && <small>{option.hint}</small>}\n {option.value === value && <svg className=\"bt-select-check\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\"><path d=\"m3 7.5 2.5 2.5L11 4.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>}\n </li>\n </Fragment>)}\n </ul>}\n </div>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Slider\n\nexport function Slider({ value, min, max, step = 1, onChange, onCommit, label, format }: { value: number; min: number; max: number; step?: number; onChange(next: number): void; onCommit?(next: number): void; label: string; format(value: number): string }) {\n const pct = ((value - min) / (max - min)) * 100;\n return <div className=\"bt-slider\">\n <input type=\"range\" min={min} max={max} step={step} value={value} aria-label={label} aria-valuetext={format(value)} style={{ '--pct': `${pct}%` } as CSSProperties}\n onChange={event => onChange(Number(event.target.value))}\n onPointerUp={event => onCommit?.(Number((event.target as HTMLInputElement).value))}\n onKeyUp={event => onCommit?.(Number((event.target as HTMLInputElement).value))}/>\n <output>{format(value)}</output>\n </div>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Color: swatches, a custom picker and a hex field\n\nexport function ColorField({ value, swatches, onChange, autoLabel, label }: { value: string | null; swatches: string[]; onChange(next: string | null): void; autoLabel?: string; label: string }) {\n const t = useT();\n const [draft, setDraft] = useState(value ?? '');\n useEffect(() => setDraft(value ?? ''), [value]);\n const custom = value && !swatches.includes(value);\n const commit = (text: string) => {\n const hex = text.trim().replace(/^([0-9a-f]{6})$/i, '#$1').toLowerCase();\n if (/^#[0-9a-f]{6}$/.test(hex)) onChange(hex); else setDraft(value ?? '');\n };\n return <div className=\"bt-color\" role=\"radiogroup\" aria-label={label}>\n {autoLabel && <button type=\"button\" role=\"radio\" aria-checked={!value} className={`bt-swatch is-auto ${!value ? 'is-on' : ''}`} onClick={() => onChange(null)}>{autoLabel}</button>}\n {swatches.map(color => <button key={color} type=\"button\" role=\"radio\" aria-checked={value === color} aria-label={color} title={color}\n className={`bt-swatch ${value === color ? 'is-on' : ''}`} style={{ '--sw': color } as CSSProperties} onClick={() => onChange(color)}/>)}\n <label className={`bt-swatch is-picker ${custom ? 'is-on' : ''}`} title={t('wb.ui.color.pick')} style={custom ? { '--sw': value } as CSSProperties : undefined}>\n <input type=\"color\" aria-label={t('wb.ui.color.custom', { label })} value={value ?? '#1d9bf0'} onChange={event => onChange(event.target.value.toLowerCase())}/>\n </label>\n <input className=\"bt-hex\" aria-label={t('wb.ui.color.hex', { label })} spellCheck={false} maxLength={7} placeholder=\"#rrggbb\" value={draft}\n onChange={event => setDraft(event.target.value)} onBlur={event => commit(event.target.value)} onKeyDown={event => { if (event.key === 'Enter') commit((event.target as HTMLInputElement).value); }}/>\n </div>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Text inputs\n\nexport function TextInput({ value, onChange, placeholder, label, type = 'text', width, onEnter, mono }: { value: string; onChange(next: string): void; placeholder?: string; label: string; type?: string; width?: number | string; onEnter?(): void; mono?: boolean }) {\n return <input className={`bt-input ${mono ? 'is-mono' : ''}`} type={type} aria-label={label} placeholder={placeholder} value={value} style={width ? { width } : undefined}\n onChange={event => onChange(event.target.value)} onKeyDown={event => { if (event.key === 'Enter') onEnter?.(); }}/>;\n}\n\n/** An input with its action button attached (Save, Add…). */\nexport function InputRow({ value, onChange, onSubmit, placeholder, label, button, disabled, mono }: { value: string; onChange(next: string): void; onSubmit(): void; placeholder?: string; label: string; button: string; disabled?: boolean; mono?: boolean }) {\n return <form className=\"bt-inputrow\" onSubmit={event => { event.preventDefault(); if (!disabled) onSubmit(); }}>\n <input className={mono ? 'is-mono' : ''} aria-label={label} placeholder={placeholder} value={value} onChange={event => onChange(event.target.value)}/>\n <button type=\"submit\" disabled={disabled}>{button}</button>\n </form>;\n}\n\nexport function SearchField({ value, onChange, placeholder, label }: { value: string; onChange(next: string): void; placeholder: string; label: string }) {\n const t = useT();\n return <label className=\"bt-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 type=\"search\" aria-label={label} placeholder={placeholder} value={value} onChange={event => onChange(event.target.value)}\n onKeyDown={event => { if (event.key === 'Escape' && value) { event.stopPropagation(); onChange(''); } }}/>\n {value && <button type=\"button\" aria-label={t('wb.ui.search.clear')} onClick={() => onChange('')}>×</button>}\n </label>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Chips: removable list items (folders, keywords)\n\nexport function ChipList({ items, onRemove, render, title, empty, icon }: { items: string[]; onRemove(item: string): void; render?(item: string): string; title?(item: string): string; empty?: string; icon?: ReactNode }) {\n const t = useT();\n if (!items.length) return empty ? <p className=\"bt-chips-empty\">{empty}</p> : null;\n return <ul className=\"bt-chips\">\n {items.map(item => <li key={item} className=\"bt-chip\" title={title?.(item) ?? item}>\n {icon}<span>{render ? render(item) : item}</span>\n <button type=\"button\" aria-label={t('wb.ui.chip.remove', { item: render ? render(item) : item })} onClick={() => onRemove(item)}>\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\"><path d=\"m2.5 2.5 5 5m0-5-5 5\" stroke=\"currentColor\" strokeWidth=\"1.4\" strokeLinecap=\"round\"/></svg>\n </button>\n </li>)}\n </ul>;\n}\n\n/** Number with − / + buttons. */\nexport function Stepper({ value, min, max, onChange, label, suffix }: { value: number; min: number; max: number; onChange(next: number): void; label: string; suffix?: string }) {\n const t = useT();\n return <div className=\"bt-stepper\" role=\"group\" aria-label={label}>\n <button type=\"button\" aria-label={t('wb.ui.stepper.decrease', { label })} disabled={value <= min} onClick={() => onChange(Math.max(min, value - 1))}>−</button>\n <output aria-live=\"polite\">{value}{suffix && <small>{suffix}</small>}</output>\n <button type=\"button\" aria-label={t('wb.ui.stepper.increase', { label })} disabled={value >= max} onClick={() => onChange(Math.min(max, value + 1))}>+</button>\n </div>;\n}\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type AreaSpec, type FeatureSpec, type FeatureTable, type Flags } from '../../runtime/featureTable.ts';
|
|
2
|
+
/** A plugin file as the Plugins list knows it (`plugins_list`). */
|
|
3
|
+
export type PluginFileState = {
|
|
4
|
+
file: string;
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
name?: string;
|
|
7
|
+
};
|
|
8
|
+
export type FeatureRow = {
|
|
9
|
+
spec: FeatureSpec;
|
|
10
|
+
/** `flag`: `features_set`; `plugin`: `plugin_set_enabled` on `spec.file`. */
|
|
11
|
+
kind: 'flag' | 'plugin';
|
|
12
|
+
/** As the owner set it. */
|
|
13
|
+
on: boolean;
|
|
14
|
+
/** A plugin-backed feature whose file is not in the plugins folder (the owner deleted it). */
|
|
15
|
+
missing: boolean;
|
|
16
|
+
/** The owner's own copy of the plugin file this feature replaced is still there (null: none). */
|
|
17
|
+
ownCopy: PluginFileState | null;
|
|
18
|
+
/** On unless the owner turned it off. */
|
|
19
|
+
isDefault: boolean;
|
|
20
|
+
/** On, but it paused itself in the focused site tab (the page changed under it). */
|
|
21
|
+
paused: boolean;
|
|
22
|
+
/** Catalog keys. */
|
|
23
|
+
label: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
export type AreaCard = {
|
|
27
|
+
area: AreaSpec;
|
|
28
|
+
/** The area's switch. */
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
groups: Array<{
|
|
31
|
+
id: string;
|
|
32
|
+
rows: FeatureRow[];
|
|
33
|
+
}>;
|
|
34
|
+
rows: FeatureRow[];
|
|
35
|
+
/** Features that are on (whatever the switch says) and how many there are. */
|
|
36
|
+
on: number;
|
|
37
|
+
total: number;
|
|
38
|
+
/** A feature with settings of its own is running: the card offers "Settings". */
|
|
39
|
+
settings: boolean;
|
|
40
|
+
/** How many of its features paused themselves in the focused site tab. */
|
|
41
|
+
paused: number;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* One card per area, in table order; rows keep the table's order inside their group. `paused`:
|
|
45
|
+
* the flags the focused site tab reported as paused (runtime featureTable `pausedFeatures`).
|
|
46
|
+
*/
|
|
47
|
+
export declare function areaCards(table: FeatureTable, flags: Readonly<Flags>, plugins: ReadonlyArray<PluginFileState>, paused?: ReadonlySet<string>): AreaCard[];
|
|
48
|
+
/** The core flags, minus the ones the app shows elsewhere (branding in Appearance, a row in Settings). */
|
|
49
|
+
export declare function fixRows(table: FeatureTable, flags: Readonly<Flags>, elsewhere?: readonly string[]): FeatureRow[];
|
|
50
|
+
/** The plugin files that are rows of a card (the Plugins list below the cards leaves them out). */
|
|
51
|
+
export declare function featureFiles(table: FeatureTable): Set<string>;
|
|
52
|
+
export type ModePlan = {
|
|
53
|
+
/** The full flag map to save. */
|
|
54
|
+
flags: Flags;
|
|
55
|
+
/** Old plugin files to turn off (a mode starts with none of them; kept when the owner keeps their changes). */
|
|
56
|
+
disable: string[];
|
|
57
|
+
/** How many of the owner's own choices the new mode would replace (flags and plugin files). */
|
|
58
|
+
changes: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* What choosing mode `to` does while on `from` (null: never chosen). With `keep`, whatever the
|
|
62
|
+
* owner changed by hand stays: flags that differ from `from`'s preset, and the old plugin files
|
|
63
|
+
* they turned on.
|
|
64
|
+
*/
|
|
65
|
+
export declare function modePlan(table: FeatureTable, flags: Readonly<Flags>, plugins: ReadonlyArray<PluginFileState>, from: string | null, to: string, keep: boolean): ModePlan;
|
|
66
|
+
/** Words the panel search matches for a row besides its label and description. */
|
|
67
|
+
export declare function rowKeywords(row: FeatureRow, area?: AreaSpec): string;
|
|
68
|
+
/** Whether every flag is what the table starts from (nothing stored). */
|
|
69
|
+
export declare const untouched: (table: FeatureTable, flags: Readonly<Flags>) => boolean;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// What the Plugins section shows of an app's feature table (runtime featureTable.ts): one card per
|
|
2
|
+
// area with its features grouped, the core flags as the Fixes list, and what choosing a mode
|
|
3
|
+
// changes. Pure (no React, no native calls), unit-tested under node.
|
|
4
|
+
//
|
|
5
|
+
// A feature's switch is its flag, or, while it is still an old plugin file that has not been ported
|
|
6
|
+
// into its area, that file's enabled state. The card shows both the same way; `kind` says which
|
|
7
|
+
// native call a toggle makes.
|
|
8
|
+
import { areaFeatures, areaFlag, coreFeatures, featureWords, manualChanges, switchMode, tableDefaults, } from "../../runtime/featureTable.js";
|
|
9
|
+
function rowOf(spec, flags, plugins, paused) {
|
|
10
|
+
const words = featureWords(spec);
|
|
11
|
+
const file = spec.backing === 'plugin' ? plugins.find(plugin => plugin.file === spec.file) : undefined;
|
|
12
|
+
const ownCopy = spec.backing !== 'plugin' && spec.supersedes ? plugins.find(plugin => plugin.file === spec.supersedes) ?? null : null;
|
|
13
|
+
return {
|
|
14
|
+
spec,
|
|
15
|
+
kind: spec.backing === 'plugin' ? 'plugin' : 'flag',
|
|
16
|
+
on: spec.backing === 'plugin' ? !!file?.enabled : flags[spec.id] === true,
|
|
17
|
+
missing: spec.backing === 'plugin' && !file,
|
|
18
|
+
ownCopy,
|
|
19
|
+
isDefault: spec.default,
|
|
20
|
+
paused: spec.backing !== 'plugin' && flags[spec.id] === true && !!paused?.has(spec.id),
|
|
21
|
+
label: words.label,
|
|
22
|
+
description: words.description,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* One card per area, in table order; rows keep the table's order inside their group. `paused`:
|
|
27
|
+
* the flags the focused site tab reported as paused (runtime featureTable `pausedFeatures`).
|
|
28
|
+
*/
|
|
29
|
+
export function areaCards(table, flags, plugins, paused) {
|
|
30
|
+
return table.areas.map(area => {
|
|
31
|
+
const enabled = flags[areaFlag(area.id)] !== false;
|
|
32
|
+
const rows = areaFeatures(table, area.id).map(spec => rowOf(spec, flags, plugins, enabled ? paused : undefined));
|
|
33
|
+
const groups = [];
|
|
34
|
+
for (const row of rows) {
|
|
35
|
+
const id = row.spec.group ?? '';
|
|
36
|
+
const group = groups.find(item => item.id === id) ?? groups[groups.push({ id, rows: [] }) - 1];
|
|
37
|
+
group.rows.push(row);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
area, enabled, groups, rows,
|
|
41
|
+
on: rows.filter(row => row.on).length,
|
|
42
|
+
total: rows.length,
|
|
43
|
+
settings: enabled && rows.some(row => row.spec.settings && row.on),
|
|
44
|
+
paused: rows.filter(row => row.paused).length,
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/** The core flags, minus the ones the app shows elsewhere (branding in Appearance, a row in Settings). */
|
|
49
|
+
export function fixRows(table, flags, elsewhere = []) {
|
|
50
|
+
return coreFeatures(table).filter(spec => !elsewhere.includes(spec.id)).map(spec => rowOf(spec, flags, []));
|
|
51
|
+
}
|
|
52
|
+
/** The plugin files that are rows of a card (the Plugins list below the cards leaves them out). */
|
|
53
|
+
export function featureFiles(table) {
|
|
54
|
+
return new Set(table.features.filter(feature => feature.backing === 'plugin' && feature.file).map(feature => feature.file));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* What choosing mode `to` does while on `from` (null: never chosen). With `keep`, whatever the
|
|
58
|
+
* owner changed by hand stays: flags that differ from `from`'s preset, and the old plugin files
|
|
59
|
+
* they turned on.
|
|
60
|
+
*/
|
|
61
|
+
export function modePlan(table, flags, plugins, from, to, keep) {
|
|
62
|
+
const files = featureFiles(table);
|
|
63
|
+
const on = plugins.filter(plugin => plugin.enabled && files.has(plugin.file)).map(plugin => plugin.file);
|
|
64
|
+
return {
|
|
65
|
+
flags: switchMode(table, flags, from, to, keep),
|
|
66
|
+
disable: keep ? [] : on,
|
|
67
|
+
changes: manualChanges(table, flags, from).length + on.length,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Words the panel search matches for a row besides its label and description. */
|
|
71
|
+
export function rowKeywords(row, area) {
|
|
72
|
+
return [row.spec.id, row.spec.keywords, row.spec.file, row.spec.supersedes, area?.name].filter(Boolean).join(' ');
|
|
73
|
+
}
|
|
74
|
+
/** Whether every flag is what the table starts from (nothing stored). */
|
|
75
|
+
export const untouched = (table, flags) => {
|
|
76
|
+
const defaults = tableDefaults(table);
|
|
77
|
+
return Object.keys(defaults).every(key => flags[key] === defaults[key]);
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=featureModel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"featureModel.js","sourceRoot":"","sources":["../../../../../../shell/src/panel/featureModel.ts"],"names":[],"mappings":"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","sourcesContent":["// What the Plugins section shows of an app's feature table (runtime featureTable.ts): one card per\n// area with its features grouped, the core flags as the Fixes list, and what choosing a mode\n// changes. Pure (no React, no native calls), unit-tested under node.\n//\n// A feature's switch is its flag, or, while it is still an old plugin file that has not been ported\n// into its area, that file's enabled state. The card shows both the same way; `kind` says which\n// native call a toggle makes.\n\nimport {\n areaFeatures, areaFlag, coreFeatures, featureWords, manualChanges, switchMode, tableDefaults,\n type AreaSpec, type FeatureSpec, type FeatureTable, type Flags,\n} from '../../../runtime/src/featureTable.ts';\n\n/** A plugin file as the Plugins list knows it (`plugins_list`). */\nexport type PluginFileState = { file: string; enabled: boolean; name?: string };\n\nexport type FeatureRow = {\n spec: FeatureSpec;\n /** `flag`: `features_set`; `plugin`: `plugin_set_enabled` on `spec.file`. */\n kind: 'flag' | 'plugin';\n /** As the owner set it. */\n on: boolean;\n /** A plugin-backed feature whose file is not in the plugins folder (the owner deleted it). */\n missing: boolean;\n /** The owner's own copy of the plugin file this feature replaced is still there (null: none). */\n ownCopy: PluginFileState | null;\n /** On unless the owner turned it off. */\n isDefault: boolean;\n /** On, but it paused itself in the focused site tab (the page changed under it). */\n paused: boolean;\n /** Catalog keys. */\n label: string;\n description: string;\n};\n\nexport type AreaCard = {\n area: AreaSpec;\n /** The area's switch. */\n enabled: boolean;\n groups: Array<{ id: string; rows: FeatureRow[] }>;\n rows: FeatureRow[];\n /** Features that are on (whatever the switch says) and how many there are. */\n on: number;\n total: number;\n /** A feature with settings of its own is running: the card offers \"Settings\". */\n settings: boolean;\n /** How many of its features paused themselves in the focused site tab. */\n paused: number;\n};\n\nfunction rowOf(spec: FeatureSpec, flags: Readonly<Flags>, plugins: ReadonlyArray<PluginFileState>, paused?: ReadonlySet<string>): FeatureRow {\n const words = featureWords(spec);\n const file = spec.backing === 'plugin' ? plugins.find(plugin => plugin.file === spec.file) : undefined;\n const ownCopy = spec.backing !== 'plugin' && spec.supersedes ? plugins.find(plugin => plugin.file === spec.supersedes) ?? null : null;\n return {\n spec,\n kind: spec.backing === 'plugin' ? 'plugin' : 'flag',\n on: spec.backing === 'plugin' ? !!file?.enabled : flags[spec.id] === true,\n missing: spec.backing === 'plugin' && !file,\n ownCopy,\n isDefault: spec.default,\n paused: spec.backing !== 'plugin' && flags[spec.id] === true && !!paused?.has(spec.id),\n label: words.label,\n description: words.description,\n };\n}\n\n/**\n * One card per area, in table order; rows keep the table's order inside their group. `paused`:\n * the flags the focused site tab reported as paused (runtime featureTable `pausedFeatures`).\n */\nexport function areaCards(table: FeatureTable, flags: Readonly<Flags>, plugins: ReadonlyArray<PluginFileState>, paused?: ReadonlySet<string>): AreaCard[] {\n return table.areas.map(area => {\n const enabled = flags[areaFlag(area.id)] !== false;\n const rows = areaFeatures(table, area.id).map(spec => rowOf(spec, flags, plugins, enabled ? paused : undefined));\n const groups: AreaCard['groups'] = [];\n for (const row of rows) {\n const id = row.spec.group ?? '';\n const group = groups.find(item => item.id === id) ?? groups[groups.push({ id, rows: [] }) - 1]!;\n group.rows.push(row);\n }\n return {\n area, enabled, groups, rows,\n on: rows.filter(row => row.on).length,\n total: rows.length,\n settings: enabled && rows.some(row => row.spec.settings && row.on),\n paused: rows.filter(row => row.paused).length,\n };\n });\n}\n\n/** The core flags, minus the ones the app shows elsewhere (branding in Appearance, a row in Settings). */\nexport function fixRows(table: FeatureTable, flags: Readonly<Flags>, elsewhere: readonly string[] = []): FeatureRow[] {\n return coreFeatures(table).filter(spec => !elsewhere.includes(spec.id)).map(spec => rowOf(spec, flags, []));\n}\n\n/** The plugin files that are rows of a card (the Plugins list below the cards leaves them out). */\nexport function featureFiles(table: FeatureTable): Set<string> {\n return new Set(table.features.filter(feature => feature.backing === 'plugin' && feature.file).map(feature => feature.file!));\n}\n\nexport type ModePlan = {\n /** The full flag map to save. */\n flags: Flags;\n /** Old plugin files to turn off (a mode starts with none of them; kept when the owner keeps their changes). */\n disable: string[];\n /** How many of the owner's own choices the new mode would replace (flags and plugin files). */\n changes: number;\n};\n\n/**\n * What choosing mode `to` does while on `from` (null: never chosen). With `keep`, whatever the\n * owner changed by hand stays: flags that differ from `from`'s preset, and the old plugin files\n * they turned on.\n */\nexport function modePlan(table: FeatureTable, flags: Readonly<Flags>, plugins: ReadonlyArray<PluginFileState>, from: string | null, to: string, keep: boolean): ModePlan {\n const files = featureFiles(table);\n const on = plugins.filter(plugin => plugin.enabled && files.has(plugin.file)).map(plugin => plugin.file);\n return {\n flags: switchMode(table, flags, from, to, keep),\n disable: keep ? [] : on,\n changes: manualChanges(table, flags, from).length + on.length,\n };\n}\n\n/** Words the panel search matches for a row besides its label and description. */\nexport function rowKeywords(row: FeatureRow, area?: AreaSpec): string {\n return [row.spec.id, row.spec.keywords, row.spec.file, row.spec.supersedes, area?.name].filter(Boolean).join(' ');\n}\n\n/** Whether every flag is what the table starts from (nothing stored). */\nexport const untouched = (table: FeatureTable, flags: Readonly<Flags>) => {\n const defaults = tableDefaults(table);\n return Object.keys(defaults).every(key => flags[key] === defaults[key]);\n};\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type FontPick = {
|
|
2
|
+
family: string[];
|
|
3
|
+
source?: 'google';
|
|
4
|
+
};
|
|
5
|
+
export declare function FontBrowser({ role, current, onPick, onClose }: {
|
|
6
|
+
role: string;
|
|
7
|
+
current: string | null;
|
|
8
|
+
onPick(pick: FontPick): void;
|
|
9
|
+
onClose(): void;
|
|
10
|
+
}): import("react").ReactPortal;
|