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 @@
|
|
|
1
|
+
{"version":3,"file":"panelMessages.js","sourceRoot":"","sources":["../../../../../../shell/src/panel/panelMessages.ts"],"names":[],"mappings":"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","sourcesContent":["// The panel's words in English (`wb.*`), the source of the framework catalogs\n// (`waybetter/locales/<bcp47>.json`). Placeholders: `{site}` is the site's name (\"X\"); the rest\n// are counts, names and paths. The panel reads the translations through the app's i18n instance\n// (setShellI18n); tests/panel.test.ts checks that every key the panel uses is here.\n\nexport const PANEL_MESSAGES = {\n 'wb.appearance.accent': 'Accent',\n 'wb.appearance.accentColor': 'Accent color',\n 'wb.appearance.accentHint': 'Links, the active tab, focus rings and filled buttons.',\n 'wb.appearance.icons': 'Icons',\n 'wb.appearance.iconsHint': 'The icons of the site and of this window. A theme may suggest a pack; your pick wins.',\n 'wb.appearance.icons.theme': 'Follow the theme',\n 'wb.appearance.icons.import': 'Import icon pack…',\n 'wb.appearance.icons.review': 'Install the icon pack “{name}”?',\n 'wb.appearance.icons.author': 'Author',\n 'wb.appearance.icons.license': 'Licence',\n 'wb.appearance.icons.source': 'Source',\n 'wb.appearance.icons.credits': 'Credits',\n 'wb.appearance.icons.size': 'Contents',\n 'wb.appearance.icons.sizeValue': '{count} icons, {size}',\n 'wb.appearance.icons.dataOnly': 'Data only: drawings, no code. The icons of the site and of this window change when you pick the pack.',\n 'wb.appearance.icons.replaces': 'An icon pack called “{name}” is already installed; this replaces it.',\n 'wb.appearance.icons.install': 'Install',\n 'wb.appearance.icons.installed': 'Installed the icon pack “{name}”.',\n 'wb.appearance.icons.remove': 'Remove {name}',\n 'wb.appearance.icons.removed': 'Removed the icon pack “{name}”.',\n 'wb.appearance.icons.imported': 'Imported icon packs',\n 'wb.appearance.doctorHints': '{count, plural, one {The theme doctor has a hint:} other {The theme doctor has # hints, the first:}} {hint}',\n 'wb.appearance.icons.site': 'The site\\'s own icons',\n 'wb.appearance.accountTheme': 'Account theme · {name}',\n 'wb.appearance.accountsHint': 'Every pane of an account shows its theme unless the pane has its own.',\n 'wb.appearance.appTheme': 'App theme · {name}',\n 'wb.appearance.askFonts': 'Download fonts for this theme',\n 'wb.appearance.askFontsText': 'Download {count, plural, one {it} other {them}} now? wayBetter fetches the font files once from fonts.googleapis.com and fonts.gstatic.com into its app data (open-source licenses). Until then the theme falls back to its other fonts.',\n 'wb.appearance.askFontsTitle': '“{name}” uses {fonts} from Google Fonts',\n 'wb.appearance.avatars': 'Avatars',\n 'wb.appearance.avatars.circle': 'Circle',\n 'wb.appearance.avatars.rounded': 'Rounded',\n 'wb.appearance.background': 'Background',\n 'wb.appearance.backgroundHint': 'The canvas around {site}\\'s columns. Text on it stays readable.',\n 'wb.appearance.basedOn': 'Based on {name}.',\n 'wb.appearance.bg.clouds': 'Clouds',\n 'wb.appearance.bg.diagonal': 'Diagonal lines',\n 'wb.appearance.bg.dots': 'Dots',\n 'wb.appearance.bg.glow': 'Glow',\n 'wb.appearance.bg.grid': 'Grid',\n 'wb.appearance.bg.image': 'Photo…',\n 'wb.appearance.bg.imageHint': 'PNG, JPEG, WebP, GIF or AVIF up to 800 KB',\n 'wb.appearance.bg.none': 'Plain',\n 'wb.appearance.bg.paper': 'Paper grain',\n 'wb.appearance.bg.scanlines': 'Scanlines',\n 'wb.appearance.bold': 'Bold weight',\n 'wb.appearance.bold.bold': 'Bold',\n 'wb.appearance.bold.heavy': 'Heavy',\n 'wb.appearance.bold.medium': 'Medium',\n 'wb.appearance.boldHint': 'Names, headings and buttons.',\n 'wb.appearance.chrome': 'Theme wayBetter’s window',\n 'wb.appearance.chromeHint': 'Tabs, address bar, titlebar and this panel take the theme’s colors and its window font. Off keeps wayBetter’s own Night Ink look.',\n 'wb.appearance.corners': 'Corners',\n 'wb.appearance.corners.crisp': 'Crisp',\n 'wb.appearance.corners.round': 'Round',\n 'wb.appearance.corners.soft': 'Soft',\n 'wb.appearance.corners.square': 'Square',\n 'wb.appearance.cornersHint': 'Cards, media, menus and buttons.',\n 'wb.appearance.crt': 'CRT overlay',\n 'wb.appearance.crtHint': 'Scanlines and a vignette over the whole page.',\n 'wb.appearance.cssApplied': 'CSS applied to {name}.',\n 'wb.appearance.cssLines': '{count, plural, one {# line} other {# lines}} · Ctrl+S applies',\n 'wb.appearance.customName': '{name} (custom)',\n 'wb.appearance.customize': 'Customize {name}',\n 'wb.appearance.customizeHint': 'Changes apply to {site} immediately and stay on top of this theme until you reset or switch themes.',\n 'wb.appearance.density': 'Density',\n 'wb.appearance.density.compact': 'Compact',\n 'wb.appearance.density.default': 'Default',\n 'wb.appearance.density.roomy': 'Roomy',\n 'wb.appearance.densityHint': 'Space around each post.',\n 'wb.appearance.dim': 'Photo dimming',\n 'wb.appearance.dimHint': 'A layer of the page color over the photo keeps the navigation legible.',\n 'wb.appearance.downloaded': 'Downloaded fonts',\n 'wb.appearance.downloadedEmpty': 'Google Fonts you pick in a font role are downloaded once and listed here.',\n 'wb.appearance.downloadedFont': 'Downloaded {family}.',\n 'wb.appearance.downloadedHint': '{count, plural, one {# Google Fonts family} other {# Google Fonts families}} · {size} in wayBetter’s app data. They work offline.',\n 'wb.appearance.families': 'Families',\n 'wb.appearance.familiesHint': 'Google Fonts are open source (SIL Open Font License 1.1 or Apache License 2.0). Removing one makes themes that use it fall back to their other fonts.',\n 'wb.appearance.followAccount': 'Follow account / app',\n 'wb.appearance.followApp': 'Follow the app theme',\n 'wb.appearance.followsApp': 'Follows the app theme · {name}',\n 'wb.appearance.fonts': 'Fonts',\n 'wb.appearance.fontsHint': 'Which font goes where. Every role inherits the interface font until you give it one: Google Fonts (downloaded once), Geist, or any installed font.',\n 'wb.appearance.hover': 'Hover',\n 'wb.appearance.hover.lift': 'Lift',\n 'wb.appearance.hover.none': 'None',\n 'wb.appearance.hover.tint': 'Tint',\n 'wb.appearance.hoverEffect': 'Hover effect',\n 'wb.appearance.hoverHint': 'What a post does under the pointer.',\n 'wb.appearance.imageTooLarge': 'That image is too large. Keep it under about 800 KB (a 1920px JPEG usually is).',\n 'wb.appearance.imageType': 'Use a PNG, JPEG, WebP, GIF or AVIF image.',\n 'wb.appearance.importJson': 'Import JSON',\n 'wb.appearance.importSafe': 'Unknown fields are ignored; unsafe values are dropped.',\n 'wb.appearance.importText': 'A .json theme document with colors, fonts, shape, layout, background and effects. Drop it here, or export any theme to see the format. Google fonts it names are downloaded only if you say so.',\n 'wb.appearance.importTitle': 'Import a theme file',\n 'wb.appearance.imported': 'Imported “{name}”.',\n 'wb.appearance.mode.auto': 'Follows {site}',\n 'wb.appearance.mode.dark': 'Dark',\n 'wb.appearance.mode.light': 'Light',\n 'wb.appearance.motion': 'Motion',\n 'wb.appearance.motion.lively': 'Lively',\n 'wb.appearance.motion.subtle': 'Subtle',\n 'wb.appearance.motionHint': 'Hover and state transitions. Reduced-motion settings are respected.',\n 'wb.appearance.noneYet': 'None yet',\n 'wb.appearance.ownTheme': 'Own theme',\n 'wb.appearance.pane': 'pane',\n 'wb.appearance.panes': 'Panes',\n 'wb.appearance.panesEmpty': 'Open {site} panes appear here.',\n 'wb.appearance.panesHint': 'A pane’s own theme wins over its account’s. Closed panes forget theirs.',\n 'wb.appearance.pasteJson': '…or paste theme JSON here',\n 'wb.appearance.percent': '{value, number, percent}',\n 'wb.appearance.px': '{value} px',\n 'wb.appearance.removeNamed': 'Remove {name}',\n 'wb.appearance.removeTheme': 'Remove theme',\n 'wb.appearance.removedFont': 'Removed {family}.',\n 'wb.appearance.removedTheme': 'Removed “{name}”.',\n 'wb.appearance.saveAsTheme': 'Save as theme',\n 'wb.appearance.saved': 'Saved “{name}”. You can export or rename it by editing the JSON.',\n 'wb.appearance.savedName': '{name} custom',\n 'wb.appearance.scopes': 'Where themes apply',\n 'wb.appearance.scopesHint': 'Give an account or a single pane its own theme. A pane’s ⋯ menu (next to Split) does the same.',\n 'wb.appearance.sidebarWidth': 'Sidebar width',\n 'wb.appearance.textSize': 'Text size',\n 'wb.appearance.textSizeHint': 'Scales {site}\\'s own text sizes.',\n 'wb.appearance.theme': 'Theme',\n 'wb.appearance.themeCss': 'Theme CSS',\n 'wb.appearance.themeCssHint': 'CSS that belongs to this theme: it is exported and saved with it. For CSS that applies to every theme, use Custom CSS below.',\n 'wb.appearance.themeCssLabel': 'CSS for this theme',\n 'wb.appearance.themeFor': 'Theme for {name}',\n 'wb.appearance.themeHint': 'A theme restyles {site} itself and this window: type, corners, density, layout, canvas and motion, with readable contrast guaranteed.',\n 'wb.appearance.themeJson': 'Theme JSON',\n 'wb.appearance.timeline': 'Timeline',\n 'wb.appearance.timeline.cards': 'Cards',\n 'wb.appearance.timeline.flat': 'Flat',\n 'wb.appearance.timeline.framed': 'Framed',\n 'wb.appearance.timelineHint': 'Flat rows, a framed column, or posts as separate cards.',\n 'wb.appearance.timelineStyle': 'Timeline style',\n 'wb.appearance.timelineWidth': 'Timeline width',\n 'wb.appearance.you': 'You',\n 'wb.appearance.yours': 'Yours',\n 'wb.backup.anotherComputer': 'another computer',\n 'wb.backup.applied': 'Applied {count, plural, one {# section} other {# sections}}.',\n 'wb.backup.applySection': 'Apply {section}',\n 'wb.backup.applySelected': 'Apply selected',\n 'wb.backup.applying': 'Applying…',\n 'wb.backup.chosen': '{count} of {total} sections · the rest stays as it is',\n 'wb.backup.comparing': 'Comparing with this computer…',\n 'wb.backup.encryptedSnapshot': 'Encrypted snapshot',\n 'wb.backup.export': 'Export settings',\n 'wb.backup.exportButton': 'Export settings…',\n 'wb.backup.exportHint': 'Themes (incl. account and pane themes), plugins you enabled and your own plugin files, custom CSS, {site} tweaks, links, keyword alerts, decks, workspaces and your account list. Never cookies, {site} sessions, tokens or keys.',\n 'wb.backup.exportedAt': 'Exported {when}',\n 'wb.backup.exporting': 'Exporting…',\n 'wb.backup.hint': 'Everything you set up, in one .waybetter file: move it to another computer or keep it safe.',\n 'wb.backup.import': 'Import settings',\n 'wb.backup.importButton': 'Import…',\n 'wb.backup.importFile': 'Import {file}',\n 'wb.backup.importHint': 'Opens a .waybetter file and shows what would change. Pick the sections to apply; nothing changes before you confirm.',\n 'wb.backup.includeDrafts': 'Include drafts',\n 'wb.backup.noKnown': 'This file has no settings wayBetter knows.',\n 'wb.backup.saved': 'Saved {file}.',\n 'wb.backup.status.changes': 'Changes',\n 'wb.backup.status.new': 'New',\n 'wb.backup.status.same': 'Same',\n 'wb.backup.syncedAgo': 'Synced {when} · encrypted snapshot',\n 'wb.backup.title': 'Backup',\n 'wb.backup.unknownDate': 'unknown date',\n 'wb.builder.adjusted': 'Adjusted {count, plural, one {# color pair} other {# color pairs}} to pass.',\n 'wb.builder.allPass': 'All pass',\n 'wb.builder.angle': 'Angle',\n 'wb.builder.author': 'Author',\n 'wb.builder.auto': 'Auto',\n 'wb.builder.autoFix': 'Auto-fix {count}',\n 'wb.builder.backgroundColor': 'Background color',\n 'wb.builder.backgroundEffects': 'Background and effects',\n 'wb.builder.buttonShape': 'Button shape',\n 'wb.builder.buttons': 'Buttons',\n 'wb.builder.cardCorners': 'Card corners',\n 'wb.builder.colors': 'Colors',\n 'wb.builder.colorsHint': 'Pick three; every other role is derived from them with the same proportions as the built-in themes. Click a role to set it by hand.',\n 'wb.builder.contrast': 'Contrast',\n 'wb.builder.contrast.accent-bg': 'Links and accent',\n 'wb.builder.contrast.accent-elevated': 'Links on hover',\n 'wb.builder.contrast.button-label': 'Post button label',\n 'wb.builder.contrast.button-page': 'Post button on the page',\n 'wb.builder.contrast.muted-bg': 'Secondary text',\n 'wb.builder.contrast.muted-surface': 'Secondary text on cards',\n 'wb.builder.contrast.text-bg': 'Text on background',\n 'wb.builder.contrast.text-page': 'Text on the page canvas',\n 'wb.builder.contrast.text-surface': 'Text on cards and menus',\n 'wb.builder.contrastHint': 'What {site} draws with this palette. wayBetter enforces these levels on {site} either way; Auto-fix makes the draft itself pass.',\n 'wb.builder.copyFailed': 'Could not copy to the clipboard.',\n 'wb.builder.cover': 'Cover',\n 'wb.builder.cssHint': 'Free-form CSS that travels with this theme (same trust as your own Custom CSS).',\n 'wb.builder.cssLines': '{count, plural, one {# line} other {# lines}} · applied live',\n 'wb.builder.deep': 'Deep',\n 'wb.builder.derived': 'Derived',\n 'wb.builder.description': 'Description',\n 'wb.builder.dimming': 'Dimming',\n 'wb.builder.fit': 'Fit',\n 'wb.builder.from': 'From',\n 'wb.builder.gradient': 'Gradient',\n 'wb.builder.gradientAngle': 'Gradient angle',\n 'wb.builder.gradientEnd': 'Gradient end',\n 'wb.builder.gradientStart': 'Gradient start',\n 'wb.builder.ink': 'Ink',\n 'wb.builder.leading': 'Post line height',\n 'wb.builder.leadingSite': '{site}\\'s',\n 'wb.builder.liveNote': 'Live on your {site} panes and this window. Nothing is saved until you save.',\n 'wb.builder.liveOff': 'Live preview on {site} is off; this miniature still follows every change.',\n 'wb.builder.liveOnSite': 'Live on {site}',\n 'wb.builder.ms': '{value} ms',\n 'wb.builder.name': 'Theme name',\n 'wb.builder.needs': 'needs {ratio}:1',\n 'wb.builder.paletteRoles': 'Palette roles',\n 'wb.builder.pattern': 'Pattern',\n 'wb.builder.patternInk': 'Pattern ink',\n 'wb.builder.patternScale': 'Pattern scale',\n 'wb.builder.patternStrength': 'Pattern strength',\n 'wb.builder.photo': 'Photo',\n 'wb.builder.photoFit': 'Photo fit',\n 'wb.builder.pill': 'Pill',\n 'wb.builder.preview': 'Preview',\n 'wb.builder.previewLive': 'Preview live on {site}',\n 'wb.builder.redo': 'Redo (Ctrl+Shift+Z)',\n 'wb.builder.regularWeight': 'Regular weight',\n 'wb.builder.replace': 'Replace…',\n 'wb.builder.role.border': 'Border',\n 'wb.builder.role.elevated': 'Elevated',\n 'wb.builder.role.inverse': 'Button',\n 'wb.builder.role.muted': 'Secondary text',\n 'wb.builder.role.onInverse': 'Button label',\n 'wb.builder.role.page': 'Page canvas',\n 'wb.builder.role.surface': 'Surface',\n 'wb.builder.saved': 'Saved “{name}” and switched to it.',\n 'wb.builder.savedMissing': 'Download {fonts} in its font roles to see {count, plural, one {it} other {them}} on {site}.',\n 'wb.builder.scale': 'Scale',\n 'wb.builder.setByHand': 'Set by hand',\n 'wb.builder.shadow': 'Shadow',\n 'wb.builder.shape': 'Shape and layout',\n 'wb.builder.share': 'Share',\n 'wb.builder.shared': 'Theme JSON copied. Anyone can paste it into Appearance → Import.',\n 'wb.builder.startFrom': 'Start from',\n 'wb.builder.startFromPlaceholder': 'Start from…',\n 'wb.builder.startedFrom': 'Started from {name}. Undo brings your draft back.',\n 'wb.builder.strength': 'Strength',\n 'wb.builder.text': 'Text',\n 'wb.builder.textColor': 'Text color',\n 'wb.builder.tile': 'Tile',\n 'wb.builder.to': 'To',\n 'wb.builder.tooLow': 'Too low',\n 'wb.builder.tracking': 'Letter spacing',\n 'wb.builder.type': 'Type',\n 'wb.builder.typeHint': 'Which font goes where. Every role inherits the interface font until you give it one.',\n 'wb.builder.undo': 'Undo (Ctrl+Z)',\n 'wb.builder.untitled': 'Untitled theme',\n 'wb.common.add': 'Add',\n 'wb.common.apply': 'Apply',\n 'wb.common.chooseFile': 'Choose file…',\n 'wb.common.clear': 'Clear',\n 'wb.common.clipboardUnavailable': 'Clipboard unavailable.',\n 'wb.common.copied': 'Copied.',\n 'wb.common.copy': 'Copy',\n 'wb.common.create': 'Create',\n 'wb.common.discard': 'Discard',\n 'wb.common.export': 'Export',\n 'wb.common.import': 'Import',\n 'wb.common.notNow': 'Not now',\n 'wb.common.removedNamed': '{name} removed.',\n 'wb.common.reset': 'Reset',\n 'wb.css.applied': 'Custom CSS applied to {site}.',\n 'wb.css.applied.short': 'Applied',\n 'wb.css.empty': 'Empty',\n 'wb.css.hint': 'Applied to every {site} tab on top of whichever theme is selected, like BetterDiscord\\'s Custom CSS. CSS for one theme goes in Theme CSS above.',\n 'wb.css.label': 'Custom CSS for {site}',\n 'wb.css.title': 'Custom CSS',\n 'wb.css.unsaved': 'Unsaved changes',\n 'wb.dev.chooseTheme': 'Choose theme file…',\n 'wb.dev.desktopOnly': 'Developer mode is available in the desktop app.',\n 'wb.dev.errors': 'Load errors',\n 'wb.dev.errorsHint': 'Syntax errors are caught before a plugin reloads (the running version stays). Errors thrown while a plugin starts show here and as a toast in the {site} tab, with file and line.',\n 'wb.dev.hint': 'For writing plugins and themes: save a file and every {site} tab updates at once. Off by default; nothing is watched while it is off.',\n 'wb.dev.mode': 'Developer mode',\n 'wb.dev.modeHint': 'Watches the plugins folder, custom.css and the theme file below. Enabled plugins reload on save (stop, then start the new version); themes and CSS apply instantly.',\n 'wb.dev.noErrors': 'No errors',\n 'wb.dev.notAvailable': 'Not available here.',\n 'wb.dev.off': 'Developer mode off.',\n 'wb.dev.on': 'Developer mode on: saved files reload in every {site} tab.',\n 'wb.dev.pluginsFolder': 'Plugins folder',\n 'wb.dev.saveToReload': 'Save a plugin, custom.css or the theme file to reload it.',\n 'wb.dev.stopWatching': 'Stop watching',\n 'wb.dev.stoppedTheme': 'Stopped watching the theme file; {site} tabs show your theme again.',\n 'wb.dev.themeFile': 'Theme file',\n 'wb.dev.themeFileHint': 'A theme .json you are editing (Appearance → Export, or npm create waybetter theme). While developer mode is on it is shown in every {site} tab as a preview; nothing is saved until you import it.',\n 'wb.dev.title': 'Live reload',\n 'wb.dev.turnOn': 'Turn developer mode on to watch your files.',\n 'wb.dev.watching': 'Watching',\n 'wb.features.areas': 'Area plugins',\n 'wb.features.areasHint': 'One plugin for each part of {site}. Switch a whole plugin off, or open it and pick its features one by one.',\n 'wb.features.count': '{on} of {total} on',\n 'wb.features.default': 'default',\n 'wb.features.fixes': 'Fixes',\n 'wb.features.fixesHint': 'On in every mode. No plugin switches them off.',\n 'wb.features.inApp': 'runs in the app',\n 'wb.features.missing': 'not installed',\n 'wb.features.off': 'Off. Its features are paused; your choices are kept.',\n 'wb.features.ownCopy': 'You have your own copy of {name}, so the built-in feature is off.',\n 'wb.features.ownCopyAsk': 'Your own copy of {name} is on. Turn it off and use the built-in one?',\n 'wb.features.paused': 'Paused in the open {site} tab: the page changed under it. Everything else keeps working; an update brings it back.',\n 'wb.features.pausedBadge': 'paused',\n 'wb.features.pluginFile': 'plugin file',\n 'wb.features.settingsNoTab': 'Open a {site} tab first, then choose Settings again.',\n 'wb.features.soon': 'Its features arrive in a later update.',\n 'wb.features.useBuiltIn': 'Use the built-in one',\n 'wb.fonts.asSite': 'As {site} draws it',\n 'wb.fonts.builtIn': 'Built-in & system',\n 'wb.fonts.category': 'Category',\n 'wb.fonts.category.all': 'All',\n 'wb.fonts.category.display': 'Display',\n 'wb.fonts.category.handwriting': 'Handwriting',\n 'wb.fonts.category.mono': 'Mono',\n 'wb.fonts.category.sans': 'Sans',\n 'wb.fonts.category.serif': 'Serif',\n 'wb.fonts.categoryName.display': 'Display',\n 'wb.fonts.categoryName.handwriting': 'Handwriting',\n 'wb.fonts.categoryName.mono': 'Monospace',\n 'wb.fonts.categoryName.sans': 'Sans serif',\n 'wb.fonts.categoryName.serif': 'Serif',\n 'wb.fonts.choice.humanist': 'Humanist (Segoe, Avenir)',\n 'wb.fonts.choice.mono': 'System mono',\n 'wb.fonts.choice.rounded': 'Rounded',\n 'wb.fonts.choice.serif': 'Serif (Charter, Georgia)',\n 'wb.fonts.choice.system': 'System UI',\n 'wb.fonts.choose': 'Choose a font',\n 'wb.fonts.chooseFor': 'Choose the font for: {role}',\n 'wb.fonts.detailEmpty': 'Pick a family to preview it with your own text, choose weights and use it for: {role}.',\n 'wb.fonts.downloadUseFor': 'Download and use for: {role}',\n 'wb.fonts.downloaded': 'Downloaded',\n 'wb.fonts.downloadedSize': 'Downloaded ({size})',\n 'wb.fonts.downloading': 'Downloading…',\n 'wb.fonts.families': 'Google Fonts families',\n 'wb.fonts.fineTune': 'Fine-tune {role}',\n 'wb.fonts.fineTuneTitle': 'Weight, size, spacing',\n 'wb.fonts.footer': 'Google Fonts are open source (SIL Open Font License 1.1 or Apache License 2.0; see each family’s page). wayBetter downloads the files you pick once, from fonts.googleapis.com and fonts.gstatic.com, into its app data; {site} never loads fonts from the web. Previews fetch only the letters shown.',\n 'wb.fonts.forRole': 'for: {role}',\n 'wb.fonts.fromWeight': 'from {weight}',\n 'wb.fonts.googleCount': '{count, plural, one {# open-source family} other {# open-source families}} from Google Fonts, previewed live.',\n 'wb.fonts.heaviest': 'Heaviest weight',\n 'wb.fonts.inUse': 'In use',\n 'wb.fonts.inheritAgain': 'Inherit again',\n 'wb.fonts.inherits': 'Inherits · {font}',\n 'wb.fonts.installedFont': 'A font installed on this computer',\n 'wb.fonts.installedPlaceholder': 'e.g. Iosevka, Avenir Next, SF Pro',\n 'wb.fonts.license': 'License and designers ↗',\n 'wb.fonts.lightest': 'Lightest weight',\n 'wb.fonts.loadingCatalog': 'Loading the catalog…',\n 'wb.fonts.monospace': 'Monospace',\n 'wb.fonts.noMatch': 'No family matches “{query}”.',\n 'wb.fonts.previewWeight': 'Preview weight',\n 'wb.fonts.role.chrome.hint': 'Tabs, address bar, titlebar and this panel.',\n 'wb.fonts.role.chrome.label': 'wayBetter window',\n 'wb.fonts.role.dialog.hint': 'Dialogs and toasts from plugins (the UI kit).',\n 'wb.fonts.role.dialog.label': 'Plugin dialogs',\n 'wb.fonts.role.heading.hint': 'Display names, profile names and page headings.',\n 'wb.fonts.role.heading.label': 'Names and headings',\n 'wb.fonts.role.interface.hint': 'All of {site}: navigation, buttons, menus. Every other role inherits it.',\n 'wb.fonts.role.interface.label': 'Interface',\n 'wb.fonts.role.mono.hint': 'Code blocks. Inherits a monospaced face.',\n 'wb.fonts.role.mono.label': 'Code',\n 'wb.fonts.role.numbers.hint': 'Like, repost and follower counts.',\n 'wb.fonts.role.numbers.label': 'Numbers',\n 'wb.fonts.role.post.hint': 'The text of posts and replies.',\n 'wb.fonts.role.post.label': 'Post text',\n 'wb.fonts.roleInherited': '{role} font: {font} (inherited). Change',\n 'wb.fonts.roleOwn': '{role} font: {font}. Change',\n 'wb.fonts.roleSize': '{role} size',\n 'wb.fonts.roleSpacing': '{role} letter spacing',\n 'wb.fonts.roleTabular': '{role} tabular figures',\n 'wb.fonts.roleWeight': '{role} weight',\n 'wb.fonts.sample': 'Sample text',\n 'wb.fonts.search': 'Search Google Fonts',\n 'wb.fonts.searchPlaceholder': 'Search Inter, Fraunces, Space Mono…',\n 'wb.fonts.showMore': 'Show {count} more of {total}',\n 'wb.fonts.size': 'Size',\n 'wb.fonts.source': 'Font source',\n 'wb.fonts.spacing': 'Spacing',\n 'wb.fonts.staticFiles': 'Each weight is a separate file (Latin and Latin Extended).',\n 'wb.fonts.systemHint': 'Fonts that ship with wayBetter, or any font installed on this computer.',\n 'wb.fonts.tabular': 'Tabular figures',\n 'wb.fonts.toWeight': 'to {weight}',\n 'wb.fonts.useFor': 'Use for: {role}',\n 'wb.fonts.useIt': 'Use it',\n 'wb.fonts.variable': 'Variable',\n 'wb.fonts.variableFile': 'One variable file covers every weight in the range (Latin and Latin Extended).',\n 'wb.fonts.variableRange': 'Variable {min}–{max}',\n 'wb.fonts.weight': 'Weight',\n 'wb.fonts.weightCount': '{count, plural, one {# weight} other {# weights}}',\n 'wb.fonts.weightsList': 'Weights {weights}',\n 'wb.fonts.weightsToDownload': 'Weights to download',\n 'wb.make.copiedDoc': '{doc} copied.',\n 'wb.make.copiedVar': '{name} copied.',\n 'wb.make.copyCommand': 'Copy: {command}',\n 'wb.make.copyMarkdown': 'Copy Markdown',\n 'wb.make.copyVar': 'Copy {name}',\n 'wb.make.create.app': 'A wayBetter app for another site',\n 'wb.make.create.plugin': 'A plugin',\n 'wb.make.create.pluginTs': 'A plugin in TypeScript',\n 'wb.make.create.theme': 'A theme',\n 'wb.make.demo.cannotUndo': 'This cannot be undone.',\n 'wb.make.demo.couldNotSave': 'Could not save',\n 'wb.make.demo.deleteNote': 'Delete this note?',\n 'wb.make.demo.exported': 'Exported',\n 'wb.make.demo.exportedText': 'Your list was saved to Downloads.',\n 'wb.make.demo.hideTrends': 'Hide trends',\n 'wb.make.demo.linkCopied': 'Link copied',\n 'wb.make.demo.min3': 'Use at least 3 characters.',\n 'wb.make.demo.myPlugin': 'My plugin',\n 'wb.make.demo.name': 'Name',\n 'wb.make.demo.postHidden': 'Post hidden',\n 'wb.make.demo.reading': 'Reading',\n 'wb.make.demo.renameList': 'Rename list',\n 'wb.make.demo.saved': 'Saved',\n 'wb.make.demo.undo': 'Undo',\n 'wb.make.demo.undoClicked': 'Undo clicked',\n 'wb.make.demo.whatHidden': 'What should be hidden?',\n 'wb.make.document': 'Document',\n 'wb.make.examples': 'Example plugins',\n 'wb.make.examplesHint': 'Pick one, change it, then copy or download the file.',\n 'wb.make.file': 'File',\n 'wb.make.fileName': 'File name',\n 'wb.make.fileRule': 'File names are letters, digits, spaces, -, _ or . and end in .plugin.js.',\n 'wb.make.fontsHint': 'The theme\\'s font roles as --wb-font and the resolved stacks. Theme files set them with font.family and font.tweet.',\n 'wb.make.inCode': 'In code',\n 'wb.make.inCodeHint': 'Plugins read the same values; plugin CSS uses the variables.',\n 'wb.make.intro': 'Plugins are one *.plugin.js file with a class that has start() and stop(); themes are one JSON file. Both use the same wayBetter API every wayBetter app has. Start from an example here, or scaffold a project:',\n 'wb.make.kit.alert': 'Alert',\n 'wb.make.kit.confirm': 'Confirm',\n 'wb.make.kit.dialog': 'Dialog',\n 'wb.make.kit.prompt': 'Prompt',\n 'wb.make.kit.toast': 'Toast',\n 'wb.make.kit.toastAction': 'Toast with Undo',\n 'wb.make.kit.toastDanger': 'Danger toast',\n 'wb.make.kit.toastSuccess': 'Success toast',\n 'wb.make.kitHint': 'What this.scope.ui opens in {site}: the same kit, in the current theme. Dialogs draw above the panes; toasts stay inside this panel.',\n 'wb.make.kitTitle': 'Plugin UI kit',\n 'wb.make.liveAfter': 'show up here.',\n 'wb.make.liveBefore': 'Live:',\n 'wb.make.liveMiddle': 'as plugins in {site} see it now. Changes in',\n 'wb.make.loadingTheme': 'Loading the theme…',\n 'wb.make.openPluginsFolder': 'Open plugins folder',\n 'wb.make.pluginCopied': 'Plugin copied.',\n 'wb.make.pluginsList': 'Plugins list:',\n 'wb.make.reference': 'Reference:',\n 'wb.make.referenceBundled': '(bundled with the app, in English).',\n 'wb.make.role.accent': 'Links, focus',\n 'wb.make.role.bg': 'Main surface',\n 'wb.make.role.border': 'Lines',\n 'wb.make.role.elevated': 'Hover, selected',\n 'wb.make.role.inverse': 'Filled button',\n 'wb.make.role.muted': 'Secondary text',\n 'wb.make.role.onAccent': 'Text on accent',\n 'wb.make.role.onInverse': 'Its label',\n 'wb.make.role.page': 'Behind the columns',\n 'wb.make.role.surface': 'Cards, inputs',\n 'wb.make.role.text': 'Text',\n 'wb.make.savedDownloads': '{file} saved to Downloads.',\n 'wb.make.siteDefaultLeading': '{site} default',\n 'wb.make.source': 'Source of {file}',\n 'wb.make.step1': 'Copy or download the file and put it in the plugins folder as {file}.',\n 'wb.make.step2After': ', press Rescan and turn it on. It starts live in every {site} tab; turning it off calls stop().',\n 'wb.make.step2Before': 'In',\n 'wb.make.step3': 'Errors show in the {site} tab\\'s console and in wayBetter.errors. wayBetter never installs plugin code by itself: only files you put in the folder run.',\n 'wb.make.tab.docs': 'Docs',\n 'wb.make.tab.kit': 'UI kit',\n 'wb.make.tab.theme': 'Theme API',\n 'wb.make.themeCopied': 'Theme copied.',\n 'wb.make.themeFile': 'A theme file',\n 'wb.make.themeFileHint': 'Three colors are enough; everything else is derived. Import it in Appearance → Import.',\n 'wb.make.warn.export': 'Export the plugin: module.exports = class \\'{ start() {} stop() {} }\\';',\n 'wb.make.warn.header': 'Start the file with a /** … */ header; without it the Plugins list shows only the file name.',\n 'wb.make.warn.permissions': 'No @permissions line: the plugin is listed as “legacy, full page access” and gets the whole API. Declare what it uses, e.g. @permissions storage, ui, network:none.',\n 'wb.make.warn.stop': 'Add stop() that undoes everything start() did (scope.dispose() does it for a scope).',\n 'wb.make.warn.tag': 'The header has no {tag}.',\n 'wb.modes.applied': '{mode} is on.',\n 'wb.modes.current': 'in use',\n 'wb.modes.custom': 'Custom (based on {mode})',\n 'wb.modes.existing': 'You already set {app} up. Nothing changes unless you pick a mode.',\n 'wb.modes.grew': '{mode} has new features: {count}.',\n 'wb.modes.keep': 'Keep my changes',\n 'wb.modes.keepHint': 'Changed by hand: {count}. Those would be replaced.',\n 'wb.modes.keepQuestion': 'Keep your manual changes?',\n 'wb.modes.keepSetup': 'Keep my current setup',\n 'wb.modes.lede': 'Pick a starting point. Every plugin and feature stays individually switchable, and you can change the mode later in Settings.',\n 'wb.modes.reapply': 'Re-apply {mode}',\n 'wb.modes.reapplyHint': 'Every feature goes back to what {mode} starts with.',\n 'wb.modes.recommended': 'Recommended',\n 'wb.modes.reset': 'Use {mode} as it is',\n 'wb.modes.review': 'Review',\n 'wb.modes.section': 'Mode',\n 'wb.modes.sectionHint': 'A starting point, not a lock. Changing it never takes a switch away.',\n 'wb.modes.start': 'Start with {mode}',\n 'wb.modes.title': 'How much should {app} change {site}?',\n 'wb.modes.turnsOff': 'Turns off: {list}',\n 'wb.modes.turnsOn': 'Turns on: {list}',\n 'wb.modes.use': 'Use this mode',\n 'wb.setup.title': 'Share my setup',\n 'wb.setup.hint': 'Your theme, icons, mode and which features are on, as one link or one small file. Anyone can use it to start from what you have.',\n 'wb.setup.shareLabel': 'Your setup',\n 'wb.setup.private': 'Nothing about you goes in it: no accounts, profiles, notes, drafts, keywords or starred messages.',\n 'wb.setup.copyLink': 'Copy link',\n 'wb.setup.linkCopied': 'Setup link copied.',\n 'wb.setup.saveFile': 'Save file',\n 'wb.setup.useLabel': 'Use a setup',\n 'wb.setup.useHint': 'Paste a waybetter://setup link or open a setup file. You see what would change before anything does.',\n 'wb.setup.paste': 'Setup link',\n 'wb.setup.preview': 'Preview',\n 'wb.setup.openFile': 'Open file…',\n 'wb.setup.changes': 'What will change',\n 'wb.setup.same': 'Nothing would change: this is already your setup.',\n 'wb.setup.theme': 'Theme: {from} → {to}',\n 'wb.setup.accent': 'Accent color: {to}',\n 'wb.setup.accentTheme': \"the theme's own\",\n 'wb.setup.icons': 'Icons: {to}',\n 'wb.setup.mode': 'Mode: {from} → {to}',\n 'wb.setup.modeNone': 'none',\n 'wb.setup.missingTheme': 'The theme “{id}” is not installed here, so yours stays.',\n 'wb.setup.missingIcons': 'The icon pack “{id}” is not installed here, so yours stays.',\n 'wb.setup.dropped': 'Left out, this version does not know them: {list}',\n 'wb.setup.apply': 'Apply',\n 'wb.setup.applied': 'Setup applied.',\n 'wb.setup.err.format': 'This is not a wayBetter setup.',\n 'wb.setup.err.version': 'This setup comes from a newer version. Update the app to use it.',\n 'wb.setup.err.app': 'This setup is for another app ({app}).',\n 'wb.setup.err.appUnknown': 'This setup is for another app.',\n 'wb.setup.err.size': 'This is too large to be a setup.',\n 'wb.panel.accounts.add': '+ Add account',\n 'wb.panel.accounts.hint': 'Each account is its own {site} sign-in on this computer and stays signed in across restarts. Click one to open its feed beside this pane.',\n 'wb.panel.accounts.newTabsBadge': 'new tabs',\n 'wb.panel.accounts.newTabsHere': 'New tabs here',\n 'wb.panel.accounts.newTabsTitle': 'New tabs (Ctrl+T) open in this account',\n 'wb.panel.accounts.openCount': '{count} open',\n 'wb.panel.accounts.openFeed': 'Open its feed beside this pane',\n 'wb.panel.accounts.removeConfirm': 'Remove “{name}” from this computer? {tabs, plural, =0 {} one {Its open tab closes, } other {Its # open tabs close, }}its sign-in and site data here are deleted. The {site} account itself is not touched.',\n 'wb.panel.accounts.signIn': 'Sign in',\n 'wb.panel.accounts.signInBeside': 'Sign in on {site} beside this pane',\n 'wb.panel.accounts.useForNewTabs': 'Use for new tabs',\n 'wb.panel.nav.label': 'wayBetter sections',\n 'wb.panel.search.for': 'for “{query}”',\n 'wb.panel.search.label': 'Search settings',\n 'wb.panel.search.none': 'No settings match',\n 'wb.panel.search.noneHint': 'Try a shorter word, like “font”, “logo” or “links”. Drafts have their own search in Drafts.',\n 'wb.panel.search.results': 'Results',\n 'wb.panel.section.accounts': 'Accounts',\n 'wb.panel.section.backup': 'Backup & sync',\n 'wb.panel.section.builder': 'Theme Builder',\n 'wb.panel.section.developer': 'Developer',\n 'wb.panel.section.home': 'wayBetter',\n 'wb.panel.section.make': 'Make',\n 'wb.panel.section.plugins': 'Plugins',\n 'wb.panel.section.power': 'Deck',\n 'wb.panel.section.settings': 'Settings',\n 'wb.panel.section.store': 'Store',\n 'wb.panel.section.themes': 'Appearance',\n 'wb.panel.section.updates': 'Updates',\n 'wb.panel.updates.checking': 'Checking for updates…',\n 'wb.panel.updates.download': 'Download',\n 'wb.panel.updates.downloading': 'Downloading an update…',\n 'wb.panel.updates.error': 'The last update check failed.',\n 'wb.panel.updates.hint': 'Signed updates are downloaded and verified natively. Tabs come back after the restart.',\n 'wb.panel.updates.idle': 'Updates are checked automatically in the background.',\n 'wb.panel.updates.installing': 'Installing the update…',\n 'wb.panel.updates.problem': 'The last update did not start correctly.',\n 'wb.panel.updates.ready': 'An update is downloaded and verified.',\n 'wb.panel.updates.restart': 'Restart & update',\n 'wb.panel.updates.upToDate': 'wayBetter for {site} is up to date.',\n 'wb.panel.updates.version': 'Version {version}',\n 'wb.plugins.deleteFile': 'Delete file',\n 'wb.plugins.enabled': '{name} enabled',\n 'wb.plugins.headerProblem': 'header problem',\n 'wb.plugins.hint': 'Install from the Store, drop a *.plugin.js file on the window (you see its code, hash and permissions first), or copy it into the plugins folder. Plugins run inside {site} with the page\\'s access; permissions limit the wayBetter API, not the page. Only install code you trust.',\n 'wb.plugins.keep': 'Keep',\n 'wb.plugins.noVersion': 'no version',\n 'wb.plugins.none': 'No plugins yet',\n 'wb.plugins.noneHint': 'Add a file like this to the plugins folder, then Rescan.',\n 'wb.plugins.openFolder': 'Open folder',\n 'wb.plugins.rescan': 'Rescan',\n 'wb.plugins.source.file': 'Dropped file',\n 'wb.plugins.source.fileTitle': 'Installed from a file you dropped',\n 'wb.plugins.source.link': 'Link',\n 'wb.plugins.started': '{name} started.',\n 'wb.plugins.stopped': '{name} stopped.',\n 'wb.plugins.title': 'JavaScript plugins',\n 'wb.power.addAccountFirst': 'Add an account first',\n 'wb.power.columnCount': '{count, plural, one {# column} other {# columns}}',\n 'wb.power.columnsFlag': 'Columns: {flag}',\n 'wb.power.comfortable': 'Comfortable',\n 'wb.power.deckCreated': '{name} deck created.',\n 'wb.power.decks': 'Decks',\n 'wb.power.decksHint': 'Presets add a ready deck; you can change every column afterwards.',\n 'wb.power.densityComfortable': 'Columns are comfortable.',\n 'wb.power.densityCompact': 'Columns are compact.',\n 'wb.power.densityHint': 'Compact trims post padding and text size inside columns.',\n 'wb.power.flagOff': '{flag}: off in columns.',\n 'wb.power.flagOn': '{flag}: on in columns.',\n 'wb.power.guard': 'Memory guard',\n 'wb.power.hint': 'A TweetDeck-style deck: {site} columns side by side, each in the account you pick. Every column is a real {site} page; posts, likes and replies are {site}’s own.',\n 'wb.power.key.column': 'Previous / next column',\n 'wb.power.key.columnHint': '[ and ] (not while typing)',\n 'wb.power.key.jump': 'Jump to column 1–9',\n 'wb.power.key.page': 'Previous / next page',\n 'wb.power.key.post': 'Post from the deck',\n 'wb.power.key.postHint': 'Ctrl+Alt+N opens {site}’s composer in the dock; you press {site}’s Post',\n 'wb.power.key.read': 'Mark column read / jump to unread',\n 'wb.power.key.toggle': 'Deck and back',\n 'wb.power.keys': 'Keys',\n 'wb.power.memory': 'Memory',\n 'wb.power.memoryHint': 'Each column is a full {site} page. Measured on the developer\\'s Windows machine: about {range} MB per column (whole app, 60 s idle).',\n 'wb.power.openDeck': 'Open deck',\n 'wb.power.park': 'Park off-page columns',\n 'wb.power.parkHint': 'Columns on another page drop caches and decoded images (WebView2’s low memory target). They keep running.',\n 'wb.power.parkOff': 'Off-page columns stay at normal memory.',\n 'wb.power.parkOn': 'Off-page columns are parked.',\n 'wb.power.perPage': 'Columns per page',\n 'wb.power.perPageGuard': 'More than {max} visible columns: about {mb} MB for the columns alone.',\n 'wb.power.perPageHint': 'Up to {count} columns on screen, about {mb} MB. The rest wait on the next page.',\n 'wb.power.perPageSaved': '{count, plural, one {# column} other {# columns}} per page.',\n 'wb.power.title': 'Deck',\n 'wb.power.width': 'Column width',\n 'wb.power.widthHint': 'New columns start at this width; a page stretches its columns to fill the window.',\n 'wb.power.widthSaved': 'New columns are {width} px wide.',\n 'wb.settings.alerts.add': 'Add keyword',\n 'wb.settings.alerts.hint': 'A desktop notification when a post {site} already showed you mentions one of your words. Matching stays on this device; at most one alert per keyword a minute.',\n 'wb.settings.alerts.keywords': 'Keywords',\n 'wb.settings.alerts.keywordsHint': 'Up to {max}. Case does not matter. Separate several with commas.',\n 'wb.settings.alerts.label': 'Alerts',\n 'wb.settings.alerts.none': 'No keywords yet.',\n 'wb.settings.alerts.onCount': 'On · {count, plural, one {# keyword} other {# keywords}}',\n 'wb.settings.alerts.stopped': 'Stopped watching “{word}”.',\n 'wb.settings.alerts.title': 'Keyword alerts',\n 'wb.settings.alerts.turnedOff': 'Keyword alerts off.',\n 'wb.settings.alerts.turnedOn': 'Keyword alerts on.',\n 'wb.settings.alerts.watching': 'Watching “{word}”.',\n 'wb.settings.alerts.watchingMore': 'Watching {count, plural, one {# more keyword} other {# more keywords}}.',\n 'wb.settings.home.hint': 'Opens on first launch and in every new tab (Ctrl+T).',\n 'wb.settings.home.label': 'Home page',\n 'wb.settings.home.reset': 'Reset to {site}',\n 'wb.settings.home.resetDone': 'Home page reset to {site}.',\n 'wb.settings.home.saved': 'Home page saved.',\n 'wb.settings.home.url': 'Home page URL',\n 'wb.settings.language.active': 'Showing {language}',\n 'wb.settings.language.communityAvailable': '{language} is available as a community translation',\n 'wb.settings.language.communitySwitch': 'Switch',\n 'wb.settings.language.followSite': 'Follow {site}',\n 'wb.settings.language.followSiteHint': 'The language your {site} account is set to',\n 'wb.settings.language.followSiteNow': 'Now: {language}',\n 'wb.settings.language.followSystem': 'Follow system',\n 'wb.settings.language.followSystemHint': 'Your computer\\'s language',\n 'wb.settings.language.groupCommunity': 'Community translations — machine-drafted, not reviewed yet',\n 'wb.settings.language.groupSupported': 'Supported languages',\n 'wb.settings.language.help': 'Help translate',\n 'wb.settings.language.helpMachine': 'This {language} translation was drafted by a machine and has not been checked by people yet. Fixes are welcome.',\n 'wb.settings.language.helpReviewed': '{language}: {percent} translated and reviewed by volunteers.',\n 'wb.settings.language.helpTitle': 'Translation',\n 'wb.settings.language.hint': 'wayBetter speaks the languages {site}\\'s own website offers. Changes apply at once to every window, {site} tab and plugin.',\n 'wb.settings.language.keywords': 'language locale translation dil sprache idioma langue',\n 'wb.settings.language.label': 'App language',\n 'wb.settings.language.machine': 'Machine-drafted',\n 'wb.settings.language.reviewed': 'Reviewed',\n 'wb.settings.language.title': 'Language',\n 'wb.settings.links.beside': 'Beside',\n 'wb.settings.links.browser': 'System browser',\n 'wb.settings.links.external': 'Links to other sites',\n 'wb.settings.links.externalHint': 'Beside opens a split next to the tab you clicked in and reuses it for the next link.',\n 'wb.settings.links.externalSaved': 'Links to other sites {how}.',\n 'wb.settings.links.hint': 'How tabs and links behave in the app.',\n 'wb.settings.links.newTab': 'New tab',\n 'wb.settings.links.opens.browser': 'open in your browser',\n 'wb.settings.links.opens.pane': 'open beside the tab',\n 'wb.settings.links.opens.same': 'open in place, as on {site}',\n 'wb.settings.links.opens.tab': 'open in a new tab',\n 'wb.settings.links.sameTab': 'Same tab',\n 'wb.settings.links.site': 'Links to {site} pages',\n 'wb.settings.links.siteHint': 'Posts, profiles, hashtags and lists you click in a timeline or hover card. Photos, videos, menus and {site}\\'s navigation always stay in place.',\n 'wb.settings.links.siteSaved': '{site} pages {how}.',\n 'wb.settings.links.title': 'Tabs and links',\n 'wb.settings.media.addFolder': 'Add folder…',\n 'wb.settings.media.cleared': 'Clipboard history cleared.',\n 'wb.settings.media.clipboard': 'Clipboard history',\n 'wb.settings.media.clipboardHint': 'Keeps your recent copied images and texts on this device, from the next copy on. Off by default.',\n 'wb.settings.media.clipboardOff': 'Clipboard history off.',\n 'wb.settings.media.clipboardOn': 'Clipboard history on.',\n 'wb.settings.media.folderRemoved': 'Folder removed.',\n 'wb.settings.media.folders': 'Gallery folders',\n 'wb.settings.media.foldersHint': 'The newest images from these folders. Only files directly inside them are read.',\n 'wb.settings.media.hint': 'The Media panel (Ctrl+Shift+G) beside {site}.',\n 'wb.settings.media.keep': 'Items to keep',\n 'wb.settings.media.keepHint': 'Older items drop off the end.',\n 'wb.settings.media.noFolders': 'No folders yet. Add one to see its images in the Media panel.',\n 'wb.settings.media.title': 'Media',\n 'wb.settings.restore.hint': 'Reopen your tabs and split layout from last time. Pinned tabs always come back.',\n 'wb.settings.restore.label': 'Restore tabs on launch',\n 'wb.settings.restore.off': 'Tabs will not be restored.',\n 'wb.settings.restore.on': 'Tabs will be restored.',\n 'wb.sync.auto': 'Sync changes automatically',\n 'wb.sync.autoHint': 'Writes a new snapshot shortly after your settings change (the last 10 of this computer are kept).',\n 'wb.sync.change': 'Change…',\n 'wb.sync.check': 'Check for newer',\n 'wb.sync.chooseFolder': 'Choose folder…',\n 'wb.sync.choosePass': 'Choose a passphrase',\n 'wb.sync.choosePassHint': 'At least 8 characters. Use the same one on your other computers. It cannot be recovered: without it the snapshots cannot be read.',\n 'wb.sync.computerName': 'This computer\\'s name',\n 'wb.sync.deriving': 'Deriving key…',\n 'wb.sync.differ': 'The passphrases differ.',\n 'wb.sync.folder': 'Sync folder',\n 'wb.sync.folderHint': 'Encrypted with a passphrase only you know (Argon2id + XChaCha20-Poly1305).',\n 'wb.sync.hint': 'Pick a folder you already sync (OneDrive, iCloud Drive, Dropbox, a network share). wayBetter writes encrypted snapshots of your settings there and offers newer ones on your other computers. No wayBetter server or account; drafts are never synced.',\n 'wb.sync.last': 'Last synced from here',\n 'wb.sync.lastHint': '{when} · {count, plural, one {# snapshot} other {# snapshots}} of this computer in the folder',\n 'wb.sync.lock': 'Lock',\n 'wb.sync.lockRemembered': 'The key is remembered on this computer (never in a backup or snapshot). Lock forgets it; you then enter the passphrase again.',\n 'wb.sync.lockSession': 'The key is kept only until wayBetter closes.',\n 'wb.sync.locked': 'Locked. Automatic sync pauses until you unlock.',\n 'wb.sync.new': 'new',\n 'wb.sync.newerFrom': 'Newer settings from {device}.',\n 'wb.sync.notYet': 'Not yet',\n 'wb.sync.nothingNewer': 'Nothing newer from your other computers.',\n 'wb.sync.now': 'Sync now',\n 'wb.sync.on': 'Encrypted · on',\n 'wb.sync.others': 'From your other computers',\n 'wb.sync.othersEmpty': 'Nothing yet. Set up sync with the same folder and passphrase on another computer.',\n 'wb.sync.othersHint': 'Review shows what would change; you pick the sections.',\n 'wb.sync.passphrase': 'Passphrase',\n 'wb.sync.passphraseLabel': 'Sync passphrase',\n 'wb.sync.problem': 'Problem',\n 'wb.sync.remember': 'Remember on this computer',\n 'wb.sync.rename': 'Rename',\n 'wb.sync.repeat': 'Repeat passphrase',\n 'wb.sync.repeatLabel': 'Repeat sync passphrase',\n 'wb.sync.review': 'Review…',\n 'wb.sync.setUp': 'Set up sync',\n 'wb.sync.setUpDone': 'Sync is set up. Your settings sync from now on.',\n 'wb.sync.stop': 'Stop syncing',\n 'wb.sync.stopped': 'Sync stopped on this computer. The folder and its snapshots stay.',\n 'wb.sync.syncing': 'Syncing…',\n 'wb.sync.thisComputer': 'This computer',\n 'wb.sync.thisComputerHint': 'How your other computers see this one.',\n 'wb.sync.title': 'Sync through a folder',\n 'wb.sync.unlock': 'Unlock',\n 'wb.sync.unlockPass': 'Unlock with your passphrase',\n 'wb.sync.unlockPassHint': 'The passphrase you chose on the computer that set up this folder.',\n 'wb.sync.unlocked': 'Unlocked.',\n 'wb.sync.written': 'Snapshot written.',\n 'wb.ui.chip.remove': 'Remove {item}',\n 'wb.ui.color.custom': '{label}: custom color',\n 'wb.ui.color.hex': '{label}: hex code',\n 'wb.ui.color.pick': 'Pick any color',\n 'wb.ui.search.clear': 'Clear search',\n 'wb.ui.select.placeholder': 'Choose…',\n 'wb.ui.stepper.decrease': 'Decrease {label}',\n 'wb.ui.stepper.increase': 'Increase {label}',\n} as const;\n\nexport type PanelKey = keyof typeof PANEL_MESSAGES;\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* The Store section is the framework's Store view (waybetter packages/shell store.css, `--wb-*`
|
|
2
|
+
tokens); here it follows the panel tokens (--c-*), so it follows the theme. */
|
|
3
|
+
|
|
4
|
+
.wbs {
|
|
5
|
+
--wb-text: var(--c-text); --wb-text-2: var(--c-text-2); --wb-text-rgb: var(--c-text-rgb); --wb-muted: var(--c-muted);
|
|
6
|
+
--wb-card: var(--c-card); --wb-field: var(--c-field);
|
|
7
|
+
--wb-border: var(--c-line); --wb-border-soft: var(--c-line-soft); --wb-border-strong: var(--c-line-strong);
|
|
8
|
+
--wb-accent: var(--c-accent); --wb-accent-rgb: var(--c-accent-rgb); --wb-accent-soft: var(--c-accent-soft);
|
|
9
|
+
--wb-ok: var(--c-ok); --wb-warn: var(--c-warn);
|
|
10
|
+
--wb-font-mono: var(--f-mono, ui-monospace, monospace); --wb-ease: var(--ease, ease);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Plugins list: permission and source badges (Extensions.tsx). */
|
|
14
|
+
.wbx-perms { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-inline-start: 6px; vertical-align: middle; }
|
|
15
|
+
.wbx-perms span { padding: 0 6px; height: 18px; display: inline-flex; align-items: center; border-radius: 5px; font: 500 10.5px/1 var(--f-mono, ui-monospace, monospace); color: var(--c-muted); background: var(--c-field); border: 1px solid var(--c-line-soft); }
|
|
16
|
+
.wbx-perms span.is-warn { color: var(--c-warn); border-color: color-mix(in srgb, var(--c-warn) 35%, transparent); }
|
|
17
|
+
.wbx-perms span.is-ok { color: var(--c-ok); border-color: color-mix(in srgb, var(--c-ok) 30%, transparent); }
|
|
18
|
+
.wbx-perms span.is-source { color: var(--c-accent); border-color: rgb(var(--c-accent-rgb) / .3); }
|
|
19
|
+
|
|
20
|
+
/* Area plugins (PluginFeatures.tsx): one card per area, its features inside. */
|
|
21
|
+
.wbf-area + .wbf-area { border-top: 1px solid var(--c-line-soft); }
|
|
22
|
+
.wbf-head { display: flex; align-items: center; gap: 12px; padding: 12px 16px; min-height: 60px; }
|
|
23
|
+
.wbf-icon { flex: none; display: grid; place-items: center; width: 34px; height: 34px; border-radius: 9px; background: var(--c-accent-soft); color: var(--c-accent); }
|
|
24
|
+
.wbf-area.is-off .wbf-icon { background: var(--c-field); color: var(--c-muted); }
|
|
25
|
+
.wbf-title { flex: 1; min-width: 0; display: grid; grid-template-columns: auto 1fr; align-items: baseline; column-gap: 8px; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: start; cursor: pointer; }
|
|
26
|
+
.wbf-title strong { font-size: 14px; font-weight: 620; }
|
|
27
|
+
.wbf-title small { grid-column: 1 / -1; margin-top: 2px; color: var(--c-muted); font-size: 12px; line-height: 1.45; }
|
|
28
|
+
.wbf-title:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 4px; border-radius: 6px; }
|
|
29
|
+
.wbf-title:disabled { cursor: default; }
|
|
30
|
+
.wbf-caret { flex: none; display: grid; color: var(--c-muted); transition: transform .14s var(--ease, ease); }
|
|
31
|
+
.wbf-caret.is-open { transform: rotate(180deg); }
|
|
32
|
+
.wbf-count { color: var(--c-muted); font: 500 11px/1 var(--f-mono, ui-monospace, monospace); }
|
|
33
|
+
.wbf-body { border-top: 1px solid var(--c-line-soft); background: color-mix(in srgb, var(--c-field) 45%, transparent); }
|
|
34
|
+
.wbf-area.is-off .wbf-body .bt-row-copy { opacity: .6; }
|
|
35
|
+
.wbf-group h3 { margin: 0; padding: 12px 16px 2px; color: var(--c-muted); font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
|
|
36
|
+
.wbf-group + .wbf-group { border-top: 1px solid var(--c-line-soft); }
|
|
37
|
+
.wbf-note { display: block; margin-top: 4px; color: var(--c-warn); }
|
|
38
|
+
.wbf-ask { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 6px; color: var(--c-text); }
|
|
39
|
+
.wbf-ask small { flex-basis: 100%; color: var(--c-muted); }
|
|
40
|
+
|
|
41
|
+
/* Modes (Modes.tsx): the first-run screen and its cards. */
|
|
42
|
+
.btp.is-onboarding { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(min-content, 1fr); justify-items: center; align-items: center; overflow: auto; }
|
|
43
|
+
.wbm-onboarding { display: flex; flex-direction: column; align-items: center; gap: 10px; width: min(880px, 100%); padding: 40px 24px; text-align: center; }
|
|
44
|
+
.wbm-onboarding > img { border-radius: 22%; }
|
|
45
|
+
.wbm-onboarding h1 { margin: 8px 0 0; font-size: 24px; font-weight: 680; letter-spacing: -.01em; text-wrap: balance; }
|
|
46
|
+
.wbm-onboarding > p { margin: 0; max-width: 58ch; color: var(--c-muted); font-size: 13px; line-height: 1.5; }
|
|
47
|
+
.wbm-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; width: 100%; margin: 18px 0 6px; }
|
|
48
|
+
.wbm-card { display: flex; flex-direction: column; gap: 8px; padding: 16px; border: 1px solid var(--c-line-soft); border-radius: 14px; background: var(--c-card); color: inherit; font: inherit; text-align: start; cursor: pointer; transition: border-color .12s var(--ease, ease), box-shadow .12s var(--ease, ease); }
|
|
49
|
+
.wbm-card:hover { border-color: var(--c-line-strong); }
|
|
50
|
+
.wbm-card.is-on { border-color: var(--c-accent); box-shadow: 0 0 0 1px var(--c-accent); }
|
|
51
|
+
.wbm-card:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }
|
|
52
|
+
.wbm-card strong { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 15px; font-weight: 640; }
|
|
53
|
+
.wbm-card > span:last-child { color: var(--c-muted); font-size: 12.5px; line-height: 1.5; }
|
|
54
|
+
.wbm-art { display: grid; place-items: center; height: 72px; border-radius: 10px; background: var(--c-field); color: var(--c-muted); }
|
|
55
|
+
.wbm-card.is-on .wbm-art { color: var(--c-accent); }
|
|
56
|
+
/* The shell's base glyph rule (16px icons) must not shrink a card's picture to a few dots. */
|
|
57
|
+
.wbm-art svg { width: 96px; height: 40px; }
|
|
58
|
+
.wbm-note { color: var(--c-text-2, var(--c-muted)); }
|
|
59
|
+
.wbm-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; margin-top: 12px; }
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type FeatureTable, type Flags } from '../../runtime/featureTable.ts';
|
|
2
|
+
export declare const SETUP_FORMAT = "waybetter-setup";
|
|
3
|
+
export declare const SETUP_VERSION = 1;
|
|
4
|
+
/** The link's scheme and path: `waybetter://setup?app=<app>&d=<data>`. */
|
|
5
|
+
export declare const SETUP_LINK = "waybetter://setup";
|
|
6
|
+
/** A setup is a few hundred bytes; anything much larger is not one. */
|
|
7
|
+
export declare const SETUP_MAX_BYTES: number;
|
|
8
|
+
export declare const SETUP_FILE_SUFFIX = ".waybetter-setup.json";
|
|
9
|
+
/** The look: a theme by id, its accent, the icon pack (absent: the theme's own). */
|
|
10
|
+
export type SetupTheme = {
|
|
11
|
+
preset: string;
|
|
12
|
+
accent: string | null;
|
|
13
|
+
icons?: string;
|
|
14
|
+
};
|
|
15
|
+
export type SharedSetup = {
|
|
16
|
+
format: typeof SETUP_FORMAT;
|
|
17
|
+
version: typeof SETUP_VERSION;
|
|
18
|
+
/** The app it is for ("x"): a setup never applies to another app. */
|
|
19
|
+
app: string;
|
|
20
|
+
theme?: SetupTheme;
|
|
21
|
+
/** The mode it started from (null: none chosen). */
|
|
22
|
+
mode?: string | null;
|
|
23
|
+
/** Feature flags that differ from the app's defaults (the rest are the defaults). */
|
|
24
|
+
flags: Flags;
|
|
25
|
+
};
|
|
26
|
+
/** What the app has now, in the terms a setup speaks. */
|
|
27
|
+
export type SetupState = {
|
|
28
|
+
theme?: SetupTheme;
|
|
29
|
+
mode: string | null;
|
|
30
|
+
flags: Flags;
|
|
31
|
+
};
|
|
32
|
+
/** The setup of `state`: only the look, the mode and the non-default flags. */
|
|
33
|
+
export declare function makeSetup(app: string, table: FeatureTable, state: SetupState): SharedSetup;
|
|
34
|
+
/** The file's text (pretty JSON). */
|
|
35
|
+
export declare const setupFile: (setup: SharedSetup) => string;
|
|
36
|
+
/** `waybetter://setup?app=x&d=<base64url of the JSON>`. */
|
|
37
|
+
export declare const setupLink: (setup: SharedSetup) => string;
|
|
38
|
+
export type SetupError = 'format' | 'version' | 'app' | 'size';
|
|
39
|
+
export type ReadSetup = {
|
|
40
|
+
ok: true;
|
|
41
|
+
setup: SharedSetup;
|
|
42
|
+
dropped: string[];
|
|
43
|
+
} | {
|
|
44
|
+
ok: false;
|
|
45
|
+
error: SetupError;
|
|
46
|
+
app?: string;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Reads a pasted link or a file's text for `app`. Everything is checked against the app's own
|
|
50
|
+
* table: an unknown flag, a mode the app does not have or a malformed theme is dropped (named in
|
|
51
|
+
* `dropped`), never guessed; a setup for another app or of another format is refused whole.
|
|
52
|
+
*/
|
|
53
|
+
export declare function readSetup(input: string, app: string, table: FeatureTable): ReadSetup;
|
|
54
|
+
export type SetupPlan = {
|
|
55
|
+
/** The theme to switch to (absent: unchanged, or not installed here: see `missingTheme`). */
|
|
56
|
+
theme?: {
|
|
57
|
+
from: string;
|
|
58
|
+
to: string;
|
|
59
|
+
};
|
|
60
|
+
accent?: {
|
|
61
|
+
from: string | null;
|
|
62
|
+
to: string | null;
|
|
63
|
+
};
|
|
64
|
+
icons?: {
|
|
65
|
+
from: string | undefined;
|
|
66
|
+
to: string | undefined;
|
|
67
|
+
};
|
|
68
|
+
/** A theme / icon pack the setup names that this app does not have: yours stays. */
|
|
69
|
+
missingTheme?: string;
|
|
70
|
+
missingIcons?: string;
|
|
71
|
+
mode?: {
|
|
72
|
+
from: string | null;
|
|
73
|
+
to: string | null;
|
|
74
|
+
};
|
|
75
|
+
/** Flags the setup turns on and off (table order). */
|
|
76
|
+
on: string[];
|
|
77
|
+
off: string[];
|
|
78
|
+
/** Nothing would change. */
|
|
79
|
+
same: boolean;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* What applying `setup` to `now` changes. `themes` / `iconPacks`: the ids installed here (plus the
|
|
83
|
+
* two icon choices every app has: undefined = the theme's own, "site" = the site's own).
|
|
84
|
+
*/
|
|
85
|
+
export declare function setupPlan(table: FeatureTable, now: SetupState, setup: SharedSetup, themes: ReadonlySet<string>, iconPacks: ReadonlySet<string>): SetupPlan;
|
|
86
|
+
/** The state after applying `plan`: only what the plan lists changes; everything else stays as it is. */
|
|
87
|
+
export declare function applySetup(table: FeatureTable, now: SetupState, plan: SetupPlan): SetupState;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// "Share my setup": one small file or one `waybetter://setup?…` link that carries how the app looks
|
|
2
|
+
// and what it does, never who uses it. It holds exactly four things: the theme (its id, the accent
|
|
3
|
+
// and the icon pack), the mode, and the feature flags that differ from the app's defaults. Nothing
|
|
4
|
+
// else can ride along: no account, profile, note, draft, starred message, keyword, workspace, custom
|
|
5
|
+
// CSS or theme file (a theme is named by id, so a theme only the sender has stays theirs).
|
|
6
|
+
//
|
|
7
|
+
// Importing never applies on its own: `setupPlan` says what would change (and what cannot, such as
|
|
8
|
+
// a theme that is not installed here), and the panel asks before `applySetup` writes anything.
|
|
9
|
+
// Pure: unit-tested in tests/setup.test.ts, used by panel/ShareSetup.tsx.
|
|
10
|
+
import { modeById, normalizeFlags, sparseFlags } from "../../runtime/featureTable.js";
|
|
11
|
+
export const SETUP_FORMAT = 'waybetter-setup';
|
|
12
|
+
export const SETUP_VERSION = 1;
|
|
13
|
+
/** The link's scheme and path: `waybetter://setup?app=<app>&d=<data>`. */
|
|
14
|
+
export const SETUP_LINK = 'waybetter://setup';
|
|
15
|
+
/** A setup is a few hundred bytes; anything much larger is not one. */
|
|
16
|
+
export const SETUP_MAX_BYTES = 16 * 1024;
|
|
17
|
+
export const SETUP_FILE_SUFFIX = '.waybetter-setup.json';
|
|
18
|
+
const ID = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
19
|
+
const COLOR = /^#[0-9a-f]{6}$/i;
|
|
20
|
+
/** The setup of `state`: only the look, the mode and the non-default flags. */
|
|
21
|
+
export function makeSetup(app, table, state) {
|
|
22
|
+
const out = { format: SETUP_FORMAT, version: SETUP_VERSION, app, flags: sparseFlags(table, state.flags) };
|
|
23
|
+
if (state.theme)
|
|
24
|
+
out.theme = { preset: state.theme.preset, accent: state.theme.accent, ...(state.theme.icons ? { icons: state.theme.icons } : {}) };
|
|
25
|
+
if (table.modes.length)
|
|
26
|
+
out.mode = modeById(table, state.mode) ? state.mode : null;
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
const toBase64Url = (text) => {
|
|
30
|
+
let binary = '';
|
|
31
|
+
for (const byte of new TextEncoder().encode(text))
|
|
32
|
+
binary += String.fromCharCode(byte);
|
|
33
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
34
|
+
};
|
|
35
|
+
const fromBase64Url = (data) => {
|
|
36
|
+
const binary = atob(data.replace(/-/g, '+').replace(/_/g, '/'));
|
|
37
|
+
return new TextDecoder('utf-8', { fatal: true }).decode(Uint8Array.from(binary, char => char.charCodeAt(0)));
|
|
38
|
+
};
|
|
39
|
+
/** The file's text (pretty JSON). */
|
|
40
|
+
export const setupFile = (setup) => `${JSON.stringify(setup, null, 2)}\n`;
|
|
41
|
+
/** `waybetter://setup?app=x&d=<base64url of the JSON>`. */
|
|
42
|
+
export const setupLink = (setup) => `${SETUP_LINK}?app=${encodeURIComponent(setup.app)}&d=${toBase64Url(JSON.stringify(setup))}`;
|
|
43
|
+
/**
|
|
44
|
+
* Reads a pasted link or a file's text for `app`. Everything is checked against the app's own
|
|
45
|
+
* table: an unknown flag, a mode the app does not have or a malformed theme is dropped (named in
|
|
46
|
+
* `dropped`), never guessed; a setup for another app or of another format is refused whole.
|
|
47
|
+
*/
|
|
48
|
+
export function readSetup(input, app, table) {
|
|
49
|
+
const text = input.trim();
|
|
50
|
+
if (new TextEncoder().encode(text).length > SETUP_MAX_BYTES)
|
|
51
|
+
return { ok: false, error: 'size' };
|
|
52
|
+
let raw;
|
|
53
|
+
try {
|
|
54
|
+
if (text.startsWith(`${SETUP_LINK}?`) || text.startsWith(`${SETUP_LINK}/?`)) {
|
|
55
|
+
const data = new URLSearchParams(text.slice(text.indexOf('?') + 1)).get('d');
|
|
56
|
+
if (!data || !/^[A-Za-z0-9_-]+$/.test(data))
|
|
57
|
+
return { ok: false, error: 'format' };
|
|
58
|
+
raw = JSON.parse(fromBase64Url(data));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
raw = JSON.parse(text);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return { ok: false, error: 'format' };
|
|
66
|
+
}
|
|
67
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
68
|
+
return { ok: false, error: 'format' };
|
|
69
|
+
const source = raw;
|
|
70
|
+
if (source.format !== SETUP_FORMAT)
|
|
71
|
+
return { ok: false, error: 'format' };
|
|
72
|
+
if (source.version !== SETUP_VERSION)
|
|
73
|
+
return { ok: false, error: 'version' };
|
|
74
|
+
if (source.app !== app)
|
|
75
|
+
return { ok: false, error: 'app', ...(typeof source.app === 'string' && ID.test(source.app) ? { app: source.app } : {}) };
|
|
76
|
+
const dropped = [];
|
|
77
|
+
const known = normalizeFlags(table, {});
|
|
78
|
+
const flags = {};
|
|
79
|
+
const inFlags = source.flags && typeof source.flags === 'object' && !Array.isArray(source.flags) ? source.flags : {};
|
|
80
|
+
for (const [key, value] of Object.entries(inFlags)) {
|
|
81
|
+
if (key in known && typeof value === 'boolean')
|
|
82
|
+
flags[key] = value;
|
|
83
|
+
else
|
|
84
|
+
dropped.push(key);
|
|
85
|
+
}
|
|
86
|
+
const setup = { format: SETUP_FORMAT, version: SETUP_VERSION, app, flags: sparseFlags(table, { ...known, ...flags }) };
|
|
87
|
+
const theme = source.theme;
|
|
88
|
+
if (theme !== undefined) {
|
|
89
|
+
const ok = theme && typeof theme === 'object' && typeof theme.preset === 'string' && ID.test(theme.preset)
|
|
90
|
+
&& (theme.accent === null || (typeof theme.accent === 'string' && COLOR.test(theme.accent)))
|
|
91
|
+
&& (theme.icons === undefined || (typeof theme.icons === 'string' && ID.test(theme.icons)));
|
|
92
|
+
if (ok)
|
|
93
|
+
setup.theme = { preset: theme.preset, accent: theme.accent, ...(theme.icons ? { icons: theme.icons } : {}) };
|
|
94
|
+
else
|
|
95
|
+
dropped.push('theme');
|
|
96
|
+
}
|
|
97
|
+
if (source.mode !== undefined) {
|
|
98
|
+
if (source.mode === null || (typeof source.mode === 'string' && modeById(table, source.mode)))
|
|
99
|
+
setup.mode = source.mode;
|
|
100
|
+
else
|
|
101
|
+
dropped.push('mode');
|
|
102
|
+
}
|
|
103
|
+
return { ok: true, setup, dropped };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* What applying `setup` to `now` changes. `themes` / `iconPacks`: the ids installed here (plus the
|
|
107
|
+
* two icon choices every app has: undefined = the theme's own, "site" = the site's own).
|
|
108
|
+
*/
|
|
109
|
+
export function setupPlan(table, now, setup, themes, iconPacks) {
|
|
110
|
+
const plan = { on: [], off: [], same: true };
|
|
111
|
+
const current = normalizeFlags(table, now.flags);
|
|
112
|
+
const next = normalizeFlags(table, setup.flags);
|
|
113
|
+
for (const key of Object.keys(current)) {
|
|
114
|
+
if (current[key] === next[key])
|
|
115
|
+
continue;
|
|
116
|
+
(next[key] ? plan.on : plan.off).push(key);
|
|
117
|
+
}
|
|
118
|
+
if (setup.theme && now.theme) {
|
|
119
|
+
if (!themes.has(setup.theme.preset))
|
|
120
|
+
plan.missingTheme = setup.theme.preset;
|
|
121
|
+
else {
|
|
122
|
+
if (setup.theme.preset !== now.theme.preset)
|
|
123
|
+
plan.theme = { from: now.theme.preset, to: setup.theme.preset };
|
|
124
|
+
if ((setup.theme.accent ?? null) !== (now.theme.accent ?? null))
|
|
125
|
+
plan.accent = { from: now.theme.accent ?? null, to: setup.theme.accent ?? null };
|
|
126
|
+
}
|
|
127
|
+
const icons = setup.theme.icons;
|
|
128
|
+
if (icons !== undefined && icons !== 'site' && !iconPacks.has(icons))
|
|
129
|
+
plan.missingIcons = icons;
|
|
130
|
+
else if (icons !== now.theme.icons)
|
|
131
|
+
plan.icons = { from: now.theme.icons, to: icons };
|
|
132
|
+
}
|
|
133
|
+
if (setup.mode !== undefined && setup.mode !== now.mode)
|
|
134
|
+
plan.mode = { from: now.mode, to: setup.mode };
|
|
135
|
+
plan.same = !plan.on.length && !plan.off.length && !plan.theme && !plan.accent && !plan.icons && !plan.mode;
|
|
136
|
+
return plan;
|
|
137
|
+
}
|
|
138
|
+
/** The state after applying `plan`: only what the plan lists changes; everything else stays as it is. */
|
|
139
|
+
export function applySetup(table, now, plan) {
|
|
140
|
+
const flags = normalizeFlags(table, now.flags);
|
|
141
|
+
for (const key of plan.on)
|
|
142
|
+
flags[key] = true;
|
|
143
|
+
for (const key of plan.off)
|
|
144
|
+
flags[key] = false;
|
|
145
|
+
let theme = now.theme;
|
|
146
|
+
if (now.theme && (plan.theme || plan.accent || plan.icons)) {
|
|
147
|
+
const icons = plan.icons ? plan.icons.to : now.theme.icons;
|
|
148
|
+
theme = { preset: plan.theme?.to ?? now.theme.preset, accent: plan.accent ? plan.accent.to : now.theme.accent, ...(icons ? { icons } : {}) };
|
|
149
|
+
}
|
|
150
|
+
return { ...(theme ? { theme } : {}), mode: plan.mode ? plan.mode.to : now.mode, flags };
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=setupModel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setupModel.js","sourceRoot":"","sources":["../../../../../../shell/src/panel/setupModel.ts"],"names":[],"mappings":"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","sourcesContent":["// \"Share my setup\": one small file or one `waybetter://setup?…` link that carries how the app looks\n// and what it does, never who uses it. It holds exactly four things: the theme (its id, the accent\n// and the icon pack), the mode, and the feature flags that differ from the app's defaults. Nothing\n// else can ride along: no account, profile, note, draft, starred message, keyword, workspace, custom\n// CSS or theme file (a theme is named by id, so a theme only the sender has stays theirs).\n//\n// Importing never applies on its own: `setupPlan` says what would change (and what cannot, such as\n// a theme that is not installed here), and the panel asks before `applySetup` writes anything.\n// Pure: unit-tested in tests/setup.test.ts, used by panel/ShareSetup.tsx.\nimport { modeById, normalizeFlags, sparseFlags, type FeatureTable, type Flags } from '../../../runtime/src/featureTable.ts';\n\nexport const SETUP_FORMAT = 'waybetter-setup';\nexport const SETUP_VERSION = 1;\n/** The link's scheme and path: `waybetter://setup?app=<app>&d=<data>`. */\nexport const SETUP_LINK = 'waybetter://setup';\n/** A setup is a few hundred bytes; anything much larger is not one. */\nexport const SETUP_MAX_BYTES = 16 * 1024;\nexport const SETUP_FILE_SUFFIX = '.waybetter-setup.json';\n\nconst ID = /^[a-z0-9][a-z0-9-]{0,63}$/;\nconst COLOR = /^#[0-9a-f]{6}$/i;\n\n/** The look: a theme by id, its accent, the icon pack (absent: the theme's own). */\nexport type SetupTheme = { preset: string; accent: string | null; icons?: string };\n\nexport type SharedSetup = {\n format: typeof SETUP_FORMAT;\n version: typeof SETUP_VERSION;\n /** The app it is for (\"x\"): a setup never applies to another app. */\n app: string;\n theme?: SetupTheme;\n /** The mode it started from (null: none chosen). */\n mode?: string | null;\n /** Feature flags that differ from the app's defaults (the rest are the defaults). */\n flags: Flags;\n};\n\n/** What the app has now, in the terms a setup speaks. */\nexport type SetupState = { theme?: SetupTheme; mode: string | null; flags: Flags };\n\n/** The setup of `state`: only the look, the mode and the non-default flags. */\nexport function makeSetup(app: string, table: FeatureTable, state: SetupState): SharedSetup {\n const out: SharedSetup = { format: SETUP_FORMAT, version: SETUP_VERSION, app, flags: sparseFlags(table, state.flags) };\n if (state.theme) out.theme = { preset: state.theme.preset, accent: state.theme.accent, ...(state.theme.icons ? { icons: state.theme.icons } : {}) };\n if (table.modes.length) out.mode = modeById(table, state.mode) ? state.mode : null;\n return out;\n}\n\nconst toBase64Url = (text: string) => {\n let binary = '';\n for (const byte of new TextEncoder().encode(text)) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n};\nconst fromBase64Url = (data: string) => {\n const binary = atob(data.replace(/-/g, '+').replace(/_/g, '/'));\n return new TextDecoder('utf-8', { fatal: true }).decode(Uint8Array.from(binary, char => char.charCodeAt(0)));\n};\n\n/** The file's text (pretty JSON). */\nexport const setupFile = (setup: SharedSetup): string => `${JSON.stringify(setup, null, 2)}\\n`;\n\n/** `waybetter://setup?app=x&d=<base64url of the JSON>`. */\nexport const setupLink = (setup: SharedSetup): string => `${SETUP_LINK}?app=${encodeURIComponent(setup.app)}&d=${toBase64Url(JSON.stringify(setup))}`;\n\nexport type SetupError = 'format' | 'version' | 'app' | 'size';\nexport type ReadSetup = { ok: true; setup: SharedSetup; dropped: string[] } | { ok: false; error: SetupError; app?: string };\n\n/**\n * Reads a pasted link or a file's text for `app`. Everything is checked against the app's own\n * table: an unknown flag, a mode the app does not have or a malformed theme is dropped (named in\n * `dropped`), never guessed; a setup for another app or of another format is refused whole.\n */\nexport function readSetup(input: string, app: string, table: FeatureTable): ReadSetup {\n const text = input.trim();\n if (new TextEncoder().encode(text).length > SETUP_MAX_BYTES) return { ok: false, error: 'size' };\n let raw: unknown;\n try {\n if (text.startsWith(`${SETUP_LINK}?`) || text.startsWith(`${SETUP_LINK}/?`)) {\n const data = new URLSearchParams(text.slice(text.indexOf('?') + 1)).get('d');\n if (!data || !/^[A-Za-z0-9_-]+$/.test(data)) return { ok: false, error: 'format' };\n raw = JSON.parse(fromBase64Url(data));\n } else {\n raw = JSON.parse(text);\n }\n } catch {\n return { ok: false, error: 'format' };\n }\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return { ok: false, error: 'format' };\n const source = raw as Record<string, unknown>;\n if (source.format !== SETUP_FORMAT) return { ok: false, error: 'format' };\n if (source.version !== SETUP_VERSION) return { ok: false, error: 'version' };\n if (source.app !== app) return { ok: false, error: 'app', ...(typeof source.app === 'string' && ID.test(source.app) ? { app: source.app } : {}) };\n\n const dropped: string[] = [];\n const known = normalizeFlags(table, {});\n const flags: Flags = {};\n const inFlags = source.flags && typeof source.flags === 'object' && !Array.isArray(source.flags) ? source.flags as Record<string, unknown> : {};\n for (const [key, value] of Object.entries(inFlags)) {\n if (key in known && typeof value === 'boolean') flags[key] = value;\n else dropped.push(key);\n }\n const setup: SharedSetup = { format: SETUP_FORMAT, version: SETUP_VERSION, app, flags: sparseFlags(table, { ...known, ...flags }) };\n\n const theme = source.theme as Record<string, unknown> | undefined;\n if (theme !== undefined) {\n const ok = theme && typeof theme === 'object' && typeof theme.preset === 'string' && ID.test(theme.preset)\n && (theme.accent === null || (typeof theme.accent === 'string' && COLOR.test(theme.accent)))\n && (theme.icons === undefined || (typeof theme.icons === 'string' && ID.test(theme.icons)));\n if (ok) setup.theme = { preset: theme.preset as string, accent: theme.accent as string | null, ...(theme.icons ? { icons: theme.icons as string } : {}) };\n else dropped.push('theme');\n }\n if (source.mode !== undefined) {\n if (source.mode === null || (typeof source.mode === 'string' && modeById(table, source.mode))) setup.mode = source.mode as string | null;\n else dropped.push('mode');\n }\n return { ok: true, setup, dropped };\n}\n\nexport type SetupPlan = {\n /** The theme to switch to (absent: unchanged, or not installed here: see `missingTheme`). */\n theme?: { from: string; to: string };\n accent?: { from: string | null; to: string | null };\n icons?: { from: string | undefined; to: string | undefined };\n /** A theme / icon pack the setup names that this app does not have: yours stays. */\n missingTheme?: string;\n missingIcons?: string;\n mode?: { from: string | null; to: string | null };\n /** Flags the setup turns on and off (table order). */\n on: string[];\n off: string[];\n /** Nothing would change. */\n same: boolean;\n};\n\n/**\n * What applying `setup` to `now` changes. `themes` / `iconPacks`: the ids installed here (plus the\n * two icon choices every app has: undefined = the theme's own, \"site\" = the site's own).\n */\nexport function setupPlan(table: FeatureTable, now: SetupState, setup: SharedSetup, themes: ReadonlySet<string>, iconPacks: ReadonlySet<string>): SetupPlan {\n const plan: SetupPlan = { on: [], off: [], same: true };\n const current = normalizeFlags(table, now.flags);\n const next = normalizeFlags(table, setup.flags);\n for (const key of Object.keys(current)) {\n if (current[key] === next[key]) continue;\n (next[key] ? plan.on : plan.off).push(key);\n }\n if (setup.theme && now.theme) {\n if (!themes.has(setup.theme.preset)) plan.missingTheme = setup.theme.preset;\n else {\n if (setup.theme.preset !== now.theme.preset) plan.theme = { from: now.theme.preset, to: setup.theme.preset };\n if ((setup.theme.accent ?? null) !== (now.theme.accent ?? null)) plan.accent = { from: now.theme.accent ?? null, to: setup.theme.accent ?? null };\n }\n const icons = setup.theme.icons;\n if (icons !== undefined && icons !== 'site' && !iconPacks.has(icons)) plan.missingIcons = icons;\n else if (icons !== now.theme.icons) plan.icons = { from: now.theme.icons, to: icons };\n }\n if (setup.mode !== undefined && setup.mode !== now.mode) plan.mode = { from: now.mode, to: setup.mode };\n plan.same = !plan.on.length && !plan.off.length && !plan.theme && !plan.accent && !plan.icons && !plan.mode;\n return plan;\n}\n\n/** The state after applying `plan`: only what the plan lists changes; everything else stays as it is. */\nexport function applySetup(table: FeatureTable, now: SetupState, plan: SetupPlan): SetupState {\n const flags = normalizeFlags(table, now.flags);\n for (const key of plan.on) flags[key] = true;\n for (const key of plan.off) flags[key] = false;\n let theme = now.theme;\n if (now.theme && (plan.theme || plan.accent || plan.icons)) {\n const icons = plan.icons ? plan.icons.to : now.theme.icons;\n theme = { preset: plan.theme?.to ?? now.theme.preset, accent: plan.accent ? plan.accent.to : now.theme.accent, ...(icons ? { icons } : {}) };\n }\n return { ...(theme ? { theme } : {}), mode: plan.mode ? plan.mode.to : now.mode, flags };\n}\n"]}
|