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,287 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { COLUMN_GAP, COLUMN_WIDTHS, isSourcePage, layoutColumns, pageOf, unreadTotal } from "../deckModel.js";
|
|
5
|
+
import { tabProfile } from "../profileModel.js";
|
|
6
|
+
import { AccountAvatar, accountName } from "./AccountSwitcher.js";
|
|
7
|
+
import { AddColumnDialog } from "./AddColumnDialog.js";
|
|
8
|
+
import { invoke } from "./bridge.js";
|
|
9
|
+
import { addColumn, bump, columnSourceUrl, configureColumn, deckById, decks, patchColumn, removeColumn, shiftColumn, } from "./deckStore.js";
|
|
10
|
+
import { FindBar } from "./FindBar.js";
|
|
11
|
+
import { useDecks, useProfiles, useT } from "./hooks.js";
|
|
12
|
+
import { Icon } from "./icons.js";
|
|
13
|
+
import { site } from "./site.js";
|
|
14
|
+
import { scheduleSync, setOverlay, shell, tabAction } from "./state.js";
|
|
15
|
+
import { useTabStill } from "./tabStill.js";
|
|
16
|
+
import './deck.css';
|
|
17
|
+
const emitDecks = () => window.dispatchEvent(new CustomEvent('bt-decks'));
|
|
18
|
+
const unreadLabel = (count) => (count > 999 ? '999+' : String(count));
|
|
19
|
+
const deckSite = () => site().deck;
|
|
20
|
+
/** Width of the columns row minus an open compose dock. */
|
|
21
|
+
function columnsWidth(total, deckId) {
|
|
22
|
+
const compose = deckSite().compose;
|
|
23
|
+
return compose && decks.compose.has(deckId) ? Math.max(0, total - compose.width - COLUMN_GAP) : total;
|
|
24
|
+
}
|
|
25
|
+
/** The row width each deck was last laid out at (for paging from keys). */
|
|
26
|
+
const rowWidths = new Map();
|
|
27
|
+
/** Focuses a column: it becomes the deck's focused column, its page is shown and its webview gets the keys. */
|
|
28
|
+
export function focusColumn(deckId, columnId, giveKeys = true) {
|
|
29
|
+
const deck = deckById(deckId);
|
|
30
|
+
const column = deck?.columns.find(c => c.id === columnId);
|
|
31
|
+
if (!deck || !column)
|
|
32
|
+
return;
|
|
33
|
+
decks.focus.set(deckId, columnId);
|
|
34
|
+
const width = columnsWidth(rowWidths.get(deckId) ?? window.innerWidth, deckId);
|
|
35
|
+
decks.page.set(deckId, pageOf(width, deck.columns, columnId, { maxVisible: decks.settings.maxVisible }, decks.page.get(deckId)));
|
|
36
|
+
emitDecks();
|
|
37
|
+
scheduleSync();
|
|
38
|
+
if (giveKeys)
|
|
39
|
+
requestAnimationFrame(() => tabAction(column.tabId, 'focus'));
|
|
40
|
+
}
|
|
41
|
+
export function runDeckCommand(deckId, command) {
|
|
42
|
+
const deck = deckById(deckId);
|
|
43
|
+
if (!deck)
|
|
44
|
+
return;
|
|
45
|
+
const focused = deck.columns.find(c => c.id === decks.focus.get(deckId)) ?? deck.columns[0];
|
|
46
|
+
const index = focused ? deck.columns.indexOf(focused) : -1;
|
|
47
|
+
const digit = /^column-([1-9])$/.exec(command);
|
|
48
|
+
if (digit) {
|
|
49
|
+
const target = deck.columns[Number(digit[1]) - 1];
|
|
50
|
+
if (target)
|
|
51
|
+
focusColumn(deckId, target.id);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
switch (command) {
|
|
55
|
+
case 'column-prev':
|
|
56
|
+
case 'column-next': {
|
|
57
|
+
const target = deck.columns[Math.min(deck.columns.length - 1, Math.max(0, index + (command === 'column-next' ? 1 : -1)))];
|
|
58
|
+
if (target)
|
|
59
|
+
focusColumn(deckId, target.id);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'column-page-prev':
|
|
63
|
+
case 'column-page-next': {
|
|
64
|
+
const width = columnsWidth(rowWidths.get(deckId) ?? window.innerWidth, deckId);
|
|
65
|
+
const layout = layoutColumns(width, deck.columns, (decks.page.get(deckId) ?? 0) + (command === 'column-page-next' ? 1 : -1), { maxVisible: decks.settings.maxVisible });
|
|
66
|
+
decks.page.set(deckId, layout.page);
|
|
67
|
+
const first = layout.visible[0];
|
|
68
|
+
if (first)
|
|
69
|
+
decks.focus.set(deckId, first.id);
|
|
70
|
+
emitDecks();
|
|
71
|
+
scheduleSync();
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case 'column-mark-read':
|
|
75
|
+
if (focused)
|
|
76
|
+
bump(focused, 'read');
|
|
77
|
+
break;
|
|
78
|
+
case 'column-jump-unread':
|
|
79
|
+
if (focused)
|
|
80
|
+
bump(focused, 'jump');
|
|
81
|
+
break;
|
|
82
|
+
case 'deck-compose':
|
|
83
|
+
toggleCompose(deckId, focused?.profile);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export function toggleCompose(deckId, profile) {
|
|
88
|
+
if (!deckSite().compose)
|
|
89
|
+
return;
|
|
90
|
+
if (decks.compose.has(deckId))
|
|
91
|
+
decks.compose.delete(deckId);
|
|
92
|
+
else
|
|
93
|
+
decks.compose.set(deckId, { profile: tabProfile(shell.profiles, profile ?? shell.profiles.active).id });
|
|
94
|
+
emitDecks();
|
|
95
|
+
scheduleSync();
|
|
96
|
+
}
|
|
97
|
+
// ---------------------------------------------------------------------------------------------
|
|
98
|
+
// Popovers (the shell rises above the tab webviews, or hides them, while one is open)
|
|
99
|
+
function Popover({ anchor, onClose, children, width = 260, label }) {
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
setOverlay(1);
|
|
102
|
+
const onKey = (event) => { if (event.key === 'Escape') {
|
|
103
|
+
event.stopPropagation();
|
|
104
|
+
onClose();
|
|
105
|
+
} };
|
|
106
|
+
window.addEventListener('keydown', onKey, true);
|
|
107
|
+
window.addEventListener('blur', onClose);
|
|
108
|
+
return () => { setOverlay(-1); window.removeEventListener('keydown', onKey, true); window.removeEventListener('blur', onClose); };
|
|
109
|
+
}, []);
|
|
110
|
+
const left = Math.max(8, Math.min(anchor.right - width, window.innerWidth - width - 8));
|
|
111
|
+
const style = { top: anchor.bottom + 6, left, width };
|
|
112
|
+
return createPortal(_jsx("div", { className: "bt-menu-backdrop", onMouseDown: onClose, onContextMenu: event => { event.preventDefault(); onClose(); }, children: _jsx("div", { className: "bt-menu bt-deck-pop bt-pop bt-pop--right", role: "dialog", "aria-label": label, style: style, onMouseDown: event => event.stopPropagation(), children: children }) }), document.body);
|
|
113
|
+
}
|
|
114
|
+
function FilterPopover({ deckId, column, anchor, onClose }) {
|
|
115
|
+
const tr = useT();
|
|
116
|
+
const [text, setText] = useState('');
|
|
117
|
+
const input = useRef(null);
|
|
118
|
+
useEffect(() => { input.current?.focus(); }, []);
|
|
119
|
+
const filters = column.filters;
|
|
120
|
+
const set = (patch) => patchColumn(deckId, column.id, { filters: { ...filters, ...patch } });
|
|
121
|
+
const add = () => {
|
|
122
|
+
const terms = text.split(/\n|,(?![^/]*\/[a-z]*$)/).map(t => t.trim()).filter(Boolean).filter(t => t.length <= 200);
|
|
123
|
+
if (!terms.length)
|
|
124
|
+
return;
|
|
125
|
+
set({ terms: [...filters.terms, ...terms.filter(t => !filters.terms.includes(t))].slice(0, 32) });
|
|
126
|
+
setText('');
|
|
127
|
+
};
|
|
128
|
+
const toggle = (key, label, hint) => _jsxs("label", { className: "bt-deck-check", children: [_jsx("input", { type: "checkbox", checked: filters[key], onChange: event => set({ [key]: event.target.checked }) }), _jsx("span", { className: "bt-deck-check-box", "aria-hidden": "true", children: _jsx(Icon, { name: "check" }) }), _jsxs("span", { className: "bt-deck-check-text", children: [_jsx("strong", { children: label }), _jsx("small", { children: hint })] })] });
|
|
129
|
+
return _jsxs(Popover, { anchor: anchor, onClose: onClose, width: 300, label: tr('wb.deck.filters.label'), children: [_jsxs("div", { className: "bt-deck-pop-head", children: [_jsx(Icon, { name: "filter" }), _jsx("strong", { children: tr('wb.deck.filters') }), _jsx("span", { children: deckSite().title(column.source, column.title).title })] }), _jsxs("div", { className: "bt-deck-terms", children: [_jsx("input", { ref: input, className: "bt-deck-input", spellCheck: false, placeholder: tr('wb.deck.mutePlaceholder'), "aria-label": tr('wb.deck.muteLabel'), value: text, onChange: event => setText(event.target.value), onKeyDown: event => { if (event.key === 'Enter') {
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
add();
|
|
132
|
+
} } }), filters.terms.length > 0 && _jsx("div", { className: "bt-deck-chips", children: filters.terms.map(term => _jsxs("span", { className: `bt-deck-chip ${/^\/.+\/[imsu]*$/.test(term) ? 'is-regex' : ''}`, children: [_jsx("span", { children: term }), _jsx("button", { type: "button", "aria-label": tr('wb.common.removeItem', { item: term }), onClick: () => set({ terms: filters.terms.filter(t => t !== term) }), children: _jsx(Icon, { name: "close" }) })] }, term)) })] }), _jsx("hr", {}), toggle('hideReplies', tr('wb.deck.hideReplies'), tr('wb.deck.hideRepliesHint')), toggle('hideReposts', tr('wb.deck.hideReposts'), tr('wb.deck.hideRepostsHint')), toggle('mediaOnly', tr('wb.deck.mediaOnly'), tr('wb.deck.mediaOnlyHint'))] });
|
|
133
|
+
}
|
|
134
|
+
function ColumnMenu({ deck, column, anchor, onClose, onRemove }) {
|
|
135
|
+
const tr = useT();
|
|
136
|
+
const index = deck.columns.indexOf(column);
|
|
137
|
+
const item = (label, icon, action, disabled = false, keys) => _jsxs("button", { role: "menuitem", disabled: disabled, onClick: () => { onClose(); action(); }, children: [_jsx(Icon, { name: icon }), _jsx("span", { className: "bt-menu-label", children: label }), keys && _jsx("span", { className: "bt-menu-keys", children: keys })] });
|
|
138
|
+
const url = decks.runtime.get(column.tabId)?.url ?? columnSourceUrl(column.source) ?? '';
|
|
139
|
+
return _jsxs(Popover, { anchor: anchor, onClose: onClose, width: 236, label: tr('wb.deck.menu'), children: [item(tr('wb.deck.markRead'), 'check', () => bump(column, 'read'), false, 'Alt R'), item(tr('wb.deck.jumpUnread'), 'history', () => bump(column, 'jump'), false, 'Alt U'), _jsx("hr", {}), item(tr('wb.deck.moveLeft'), 'back', () => shiftColumn(deck.id, column.id, -1), index <= 0), item(tr('wb.deck.moveRight'), 'forward', () => shiftColumn(deck.id, column.id, 1), index >= deck.columns.length - 1), _jsxs("div", { className: "bt-deck-widths", role: "group", "aria-label": tr('wb.deck.widthLabel'), children: [_jsx("span", { children: tr('wb.deck.width') }), COLUMN_WIDTHS.map(width => _jsx("button", { type: "button", "aria-pressed": column.width === width, className: column.width === width ? 'is-on' : '', onClick: () => { patchColumn(deck.id, column.id, { width }); scheduleSync(); }, children: width }, width))] }), _jsx("hr", {}), item(tr('wb.shell.menu.duplicate'), 'duplicate', () => addColumn(deck.id, { profile: column.profile, source: column.source, filters: column.filters, flags: column.flags, width: column.width }, column.id)), item(tr('wb.deck.openAsTab'), 'external', () => shell.openUrl(url, column.profile), !url), _jsx("hr", {}), item(tr('wb.deck.remove'), 'trash', onRemove)] });
|
|
140
|
+
}
|
|
141
|
+
// ---------------------------------------------------------------------------------------------
|
|
142
|
+
// One column: header strip + the placeholder its webview covers
|
|
143
|
+
function ColumnView({ deck, column, x, width, focused, number }) {
|
|
144
|
+
const tr = useT();
|
|
145
|
+
const profiles = useProfiles();
|
|
146
|
+
const body = useRef(null);
|
|
147
|
+
const still = useTabStill(column.tabId);
|
|
148
|
+
const [menu, setMenu] = useState(null);
|
|
149
|
+
const [leaving, setLeaving] = useState(false);
|
|
150
|
+
// Find in page for this column (Ctrl+F pressed in it): the find bar lies over the column's header.
|
|
151
|
+
const [finding, setFinding] = useState(false);
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
const openFindBar = (event) => { if (event.detail === column.tabId)
|
|
154
|
+
setFinding(true); };
|
|
155
|
+
window.addEventListener('bt-find', openFindBar);
|
|
156
|
+
return () => window.removeEventListener('bt-find', openFindBar);
|
|
157
|
+
}, [column.tabId]);
|
|
158
|
+
const spec = deckSite();
|
|
159
|
+
const runtime = decks.runtime.get(column.tabId);
|
|
160
|
+
const account = tabProfile(profiles, column.profile);
|
|
161
|
+
const type = spec.kinds.find(kind => kind.kind === column.source.kind);
|
|
162
|
+
const { title, detail } = spec.title(column.source, column.title);
|
|
163
|
+
const source = columnSourceUrl(column.source);
|
|
164
|
+
const away = !!(runtime?.url && source && !isSourcePage(runtime.url, source));
|
|
165
|
+
const unread = runtime?.unread ?? 0;
|
|
166
|
+
const filtered = column.filters.terms.length > 0 || column.filters.hideReplies || column.filters.hideReposts || column.filters.mediaOnly;
|
|
167
|
+
const pageTitle = spec.pageTitle ?? ((text) => text);
|
|
168
|
+
useLayoutEffect(() => {
|
|
169
|
+
const el = body.current;
|
|
170
|
+
if (!el || leaving)
|
|
171
|
+
return;
|
|
172
|
+
shell.placeholders.set(column.tabId, el);
|
|
173
|
+
const observer = new ResizeObserver(scheduleSync);
|
|
174
|
+
observer.observe(el);
|
|
175
|
+
scheduleSync();
|
|
176
|
+
return () => {
|
|
177
|
+
observer.disconnect();
|
|
178
|
+
if (shell.placeholders.get(column.tabId) === el)
|
|
179
|
+
shell.placeholders.delete(column.tabId);
|
|
180
|
+
scheduleSync();
|
|
181
|
+
};
|
|
182
|
+
}, [column.tabId, leaving]);
|
|
183
|
+
// Position changes (paging, reordering, width) move the webview with the placeholder.
|
|
184
|
+
useEffect(() => { scheduleSync(); }, [x, width]);
|
|
185
|
+
const open = (kind) => (event) => setMenu(menu?.kind === kind ? null : { kind, anchor: event.currentTarget.getBoundingClientRect() });
|
|
186
|
+
const remove = () => {
|
|
187
|
+
setLeaving(true);
|
|
188
|
+
// The webview hides at once (no placeholder); the header slides out, then the column goes.
|
|
189
|
+
const reduced = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
|
190
|
+
setTimeout(() => removeColumn(deck.id, column.id), reduced ? 0 : 180);
|
|
191
|
+
};
|
|
192
|
+
return _jsxs("section", { className: `bt-col${focused ? ' is-focused' : ''}${leaving ? ' is-leaving' : ''}`, style: { left: x, width, ['--bt-col-account']: account.color }, "aria-label": tr('wb.deck.columnLabel', { title }), onMouseDown: () => { if (!focused)
|
|
193
|
+
focusColumn(deck.id, column.id, false); }, children: [_jsxs("header", { className: "bt-col-head", children: [away
|
|
194
|
+
? _jsx("button", { className: "bt-col-glyph bt-col-back", title: tr('wb.deck.backTo', { title }), "aria-label": tr('wb.deck.backTo', { title }), onClick: () => { if (source)
|
|
195
|
+
invoke('tab_navigate', { id: column.tabId, url: source }).catch(() => { }); }, children: _jsx(Icon, { name: "back" }) })
|
|
196
|
+
: _jsx("span", { className: "bt-col-glyph", "aria-hidden": "true", children: _jsx(Icon, { name: type?.icon ?? 'globe' }) }), _jsxs("div", { className: "bt-col-titles", title: detail ? `${title} · ${detail}` : title, children: [_jsx("strong", { children: title }), _jsx("span", { children: away ? (pageTitle(runtime?.title ?? '') || tr('wb.deck.viewingPost')) : detail ?? `${site().accounts.handlePrefix}${account.account?.handle ?? account.name}` })] }), unread > 0 && _jsx("button", { className: "bt-col-unread", title: tr('wb.deck.jumpUnreadTitle'), "aria-label": tr('wb.deck.unreadLabel', { count: unread }), onClick: () => bump(column, 'jump'), children: unreadLabel(unread) }), _jsx("span", { className: "bt-col-fill" }), _jsx("span", { className: "bt-col-account", title: tr('wb.shell.tab.account', { name: accountName(account) }), children: _jsx(AccountAvatar, { profile: account, size: 20 }) }), _jsx("button", { className: `bt-icon bt-col-btn${filtered ? ' is-active' : ''}`, title: tr('wb.deck.filters'), "aria-label": tr('wb.deck.filters'), "aria-haspopup": "dialog", "aria-expanded": menu?.kind === 'filters', onClick: open('filters'), children: _jsx(Icon, { name: "filter" }) }), _jsx("button", { className: "bt-icon bt-col-btn", title: tr('wb.deck.menu'), "aria-label": tr('wb.deck.menu'), "aria-haspopup": "menu", "aria-expanded": menu?.kind === 'menu', onClick: open('menu'), children: _jsx("svg", { className: "bt-glyph", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M6 12h.01M12 12h.01M18 12h.01", strokeWidth: "3" }) }) }), number <= 9 && _jsx("span", { className: "bt-col-key", "aria-hidden": "true", children: number }), runtime?.loading && _jsx("span", { className: "bt-col-progress", "aria-label": tr('wb.common.loading') }), finding && _jsx("div", { className: "bt-col-find", children: _jsx(FindBar, { tabId: column.tabId, url: runtime?.url ?? source ?? '', onClose: () => setFinding(false) }) })] }), _jsx("div", { className: "bt-col-body", ref: body, children: still
|
|
197
|
+
? _jsx("div", { className: "bt-still", "aria-hidden": "true", style: { backgroundImage: `url("${still}")` } })
|
|
198
|
+
: _jsxs("div", { className: "bt-col-hint", children: [_jsx("span", { className: "bt-spinner", "aria-hidden": "true" }), _jsx("span", { children: title })] }) }), menu?.kind === 'filters' && _jsx(FilterPopover, { deckId: deck.id, column: column, anchor: menu.anchor, onClose: () => setMenu(null) }), menu?.kind === 'menu' && _jsx(ColumnMenu, { deck: deck, column: column, anchor: menu.anchor, onClose: () => setMenu(null), onRemove: remove })] });
|
|
199
|
+
}
|
|
200
|
+
// ---------------------------------------------------------------------------------------------
|
|
201
|
+
function EmptyDeck({ deck, onAdd }) {
|
|
202
|
+
const tr = useT();
|
|
203
|
+
const profiles = useProfiles();
|
|
204
|
+
const ids = profiles.profiles.map(p => p.id);
|
|
205
|
+
const ordered = [profiles.active, ...ids.filter(id => id !== profiles.active)];
|
|
206
|
+
return _jsxs("div", { className: "bt-deck-empty bt-rise", children: [_jsx("div", { className: "bt-deck-empty-art", "aria-hidden": "true", children: [0, 1, 2, 3].map(i => _jsx("span", { style: { animationDelay: `${i * 70}ms` } }, i)) }), _jsx("h2", { children: tr('wb.deck.title') }), _jsx("p", { children: tr('wb.deck.emptyHint', { site: site().name }) }), _jsxs("div", { className: "bt-deck-empty-actions", children: [_jsxs("button", { className: "bt-deck-primary", onClick: onAdd, children: [_jsx(Icon, { name: "plus" }), tr('wb.deck.addColumn')] }), (deckSite().presets ?? []).map(preset => {
|
|
207
|
+
const needs = preset.needsTwoAccounts && ids.length < 2 ? preset.needsTwoAccounts() : undefined;
|
|
208
|
+
return _jsx("button", { className: "bt-deck-secondary", disabled: !!needs, title: needs, onClick: () => { for (const column of preset.columns(ordered))
|
|
209
|
+
addColumn(deck.id, column); }, children: preset.label() }, preset.id);
|
|
210
|
+
})] }), _jsxs("p", { className: "bt-deck-empty-keys", children: [_jsxs("span", { children: [_jsx("span", { className: "bt-kbd", children: "[" }), _jsx("span", { className: "bt-kbd", children: "]" }), " ", tr('wb.deck.key.columns')] }), _jsxs("span", { children: [_jsx("span", { className: "bt-kbd", children: "Alt" }), _jsx("span", { className: "bt-kbd", children: "1\u20139" }), " ", tr('wb.deck.key.jump')] }), _jsxs("span", { children: [_jsx("span", { className: "bt-kbd", children: "Alt" }), _jsx("span", { className: "bt-kbd", children: "R" }), " ", tr('wb.deck.key.read')] }), deckSite().compose && _jsxs("span", { children: [_jsx("span", { className: "bt-kbd", children: "Ctrl" }), _jsx("span", { className: "bt-kbd", children: "Alt" }), _jsx("span", { className: "bt-kbd", children: "N" }), " ", tr('wb.deck.key.post')] })] })] });
|
|
211
|
+
}
|
|
212
|
+
export function DeckView(props) {
|
|
213
|
+
const tr = useT();
|
|
214
|
+
useDecks();
|
|
215
|
+
const deckId = props.params.deckId;
|
|
216
|
+
const row = useRef(null);
|
|
217
|
+
const [rowWidth, setRowWidth] = useState(0);
|
|
218
|
+
const [adding, setAdding] = useState(false);
|
|
219
|
+
const deck = deckById(deckId);
|
|
220
|
+
const compose = deckSite().compose;
|
|
221
|
+
useLayoutEffect(() => {
|
|
222
|
+
const el = row.current;
|
|
223
|
+
if (!el)
|
|
224
|
+
return;
|
|
225
|
+
const measure = () => { const w = Math.floor(el.getBoundingClientRect().width); rowWidths.set(deckId, w); setRowWidth(w); };
|
|
226
|
+
const observer = new ResizeObserver(measure);
|
|
227
|
+
observer.observe(el);
|
|
228
|
+
measure();
|
|
229
|
+
return () => observer.disconnect();
|
|
230
|
+
}, [deckId, !!deck]);
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
const visibility = props.api.onDidVisibilityChange(scheduleSync);
|
|
233
|
+
// The palette's "Add column…" opens this deck's dialog.
|
|
234
|
+
const add = (event) => { if (event.detail === deckId)
|
|
235
|
+
setAdding(true); };
|
|
236
|
+
window.addEventListener('bt-deck-add', add);
|
|
237
|
+
return () => { visibility.dispose(); window.removeEventListener('bt-deck-add', add); };
|
|
238
|
+
}, [props.api, deckId]);
|
|
239
|
+
// Every column gets its config before its webview exists (no flash of the site's chrome);
|
|
240
|
+
// unmounting the deck forgets what was sent, so reopening it configures again.
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
if (!deck)
|
|
243
|
+
return;
|
|
244
|
+
for (const column of deck.columns) {
|
|
245
|
+
if (decks.sent.has(column.tabId))
|
|
246
|
+
continue;
|
|
247
|
+
void configureColumn(column, true).then(() => { decks.ready.add(column.tabId); scheduleSync(); });
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
useEffect(() => () => {
|
|
251
|
+
for (const column of deckById(deckId)?.columns ?? []) {
|
|
252
|
+
decks.sent.delete(column.tabId);
|
|
253
|
+
decks.ready.delete(column.tabId);
|
|
254
|
+
}
|
|
255
|
+
}, [deckId]);
|
|
256
|
+
if (!deck) {
|
|
257
|
+
return _jsx("div", { className: "bt-deck", children: _jsxs("div", { className: "bt-deck-empty", children: [_jsx("h2", { children: tr('wb.deck.gone') }), _jsx("p", { children: tr('wb.deck.goneHint') }), _jsx("button", { className: "bt-deck-secondary", onClick: () => props.api.close(), children: tr('wb.shell.menu.close') })] }) });
|
|
258
|
+
}
|
|
259
|
+
const settings = decks.settings;
|
|
260
|
+
const width = columnsWidth(rowWidth, deck.id);
|
|
261
|
+
const layout = layoutColumns(width, deck.columns, decks.page.get(deck.id) ?? 0, { maxVisible: settings.maxVisible });
|
|
262
|
+
const focusedId = decks.focus.get(deck.id) ?? layout.visible[0]?.id;
|
|
263
|
+
const total = unreadTotal(new Map(deck.columns.map(c => [c.tabId, decks.runtime.get(c.tabId)?.unread ?? 0])), deck.columns);
|
|
264
|
+
const setPage = (page) => { decks.page.set(deck.id, page); emitDecks(); scheduleSync(); };
|
|
265
|
+
const composing = compose && decks.compose.get(deck.id);
|
|
266
|
+
const overLimit = deck.columns.length > settings.maxVisible;
|
|
267
|
+
return _jsxs("div", { className: "bt-deck", children: [_jsxs("div", { className: "bt-deck-bar", children: [_jsx("span", { className: "bt-deck-mark", "aria-hidden": "true", children: _jsx(Icon, { name: "grid" }) }), _jsx("strong", { className: "bt-deck-name", children: deck.name }), _jsx("span", { className: "bt-deck-count", children: tr('wb.deck.columnCount', { count: deck.columns.length }) }), total > 0 && _jsx("span", { className: "bt-deck-total", title: tr('wb.deck.unreadTitle'), children: tr('wb.deck.newCount', { count: unreadLabel(total) }) }), _jsx("span", { className: "bt-deck-fill" }), layout.pages > 1 && _jsxs("div", { className: "bt-deck-pager", role: "group", "aria-label": tr('wb.deck.pages'), children: [_jsx("button", { className: "bt-icon", title: tr('wb.deck.prevTitle'), "aria-label": tr('wb.deck.prev'), disabled: layout.page === 0, onClick: () => setPage(layout.page - 1), children: _jsx(Icon, { name: "back" }) }), Array.from({ length: layout.pages }, (_, i) => _jsx("button", { className: `bt-deck-dot${i === layout.page ? ' is-on' : ''}`, "aria-label": tr('wb.deck.page', { n: i + 1 }), "aria-current": i === layout.page ? 'page' : undefined, onClick: () => setPage(i) }, i)), _jsx("button", { className: "bt-icon", title: tr('wb.deck.nextTitle'), "aria-label": tr('wb.deck.next'), disabled: layout.page >= layout.pages - 1, onClick: () => setPage(layout.page + 1), children: _jsx(Icon, { name: "forward" }) })] }), overLimit && _jsx("span", { className: "bt-deck-memory", title: tr('wb.deck.memoryTitle', { count: decks.settings.maxVisible, site: site().name }), children: tr('wb.deck.onScreen', { visible: layout.visible.length, total: deck.columns.length }) }), _jsxs("button", { className: "bt-deck-action", onClick: () => setAdding(true), title: tr('wb.deck.addColumn'), children: [_jsx(Icon, { name: "plus" }), _jsx("span", { children: tr('wb.deck.column') })] }), compose && _jsxs("button", { className: `bt-deck-action${composing ? ' is-on' : ''}`, onClick: () => toggleCompose(deck.id, deck.columns.find(c => c.id === focusedId)?.profile), title: tr('wb.deck.postTitle'), "aria-pressed": !!composing, children: [_jsx(Icon, { name: "edit" }), _jsx("span", { children: tr('wb.deck.post') })] }), _jsx("button", { className: "bt-icon bt-deck-settings", title: tr('wb.deck.settings'), "aria-label": tr('wb.deck.settings'), onClick: () => shell.openPanelSection('power'), children: _jsx(Icon, { name: "settings" }) })] }), _jsxs("div", { className: "bt-deck-row", ref: row, children: [deck.columns.length === 0
|
|
268
|
+
? _jsx(EmptyDeck, { deck: deck, onAdd: () => setAdding(true) })
|
|
269
|
+
: layout.visible.map(place => {
|
|
270
|
+
const column = deck.columns.find(c => c.id === place.id);
|
|
271
|
+
return _jsx(ColumnView, { deck: deck, column: column, x: place.x, width: place.width, focused: column.id === focusedId, number: deck.columns.indexOf(column) + 1 }, column.id);
|
|
272
|
+
}), compose && composing && _jsx(compose.Dock, { deckId: deck.id, left: width + COLUMN_GAP })] }), adding && _jsx(AddColumnDialog, { deck: deck, onClose: () => setAdding(false), onAdd: input => {
|
|
273
|
+
const column = addColumn(deck.id, input);
|
|
274
|
+
void configureColumn(column, true).then(() => { decks.ready.add(column.tabId); focusColumn(deck.id, column.id, false); });
|
|
275
|
+
setAdding(false);
|
|
276
|
+
} })] });
|
|
277
|
+
}
|
|
278
|
+
/** Unread total of a deck on its dockview tab. */
|
|
279
|
+
export function DeckTabBadge({ deckId }) {
|
|
280
|
+
useDecks();
|
|
281
|
+
const deck = deckById(deckId);
|
|
282
|
+
if (!deck)
|
|
283
|
+
return null;
|
|
284
|
+
const total = unreadTotal(new Map(deck.columns.map(c => [c.tabId, decks.runtime.get(c.tabId)?.unread ?? 0])), deck.columns);
|
|
285
|
+
return total > 0 ? _jsx("span", { className: "bt-tab-unread", "aria-label": `${total} unread`, children: unreadLabel(total) }) : null;
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=DeckView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeckView.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/DeckView.tsx"],"names":[],"mappings":"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","sourcesContent":["// Decks: site columns side by side in one shell tab (dockview component `deck`). The shell draws\n// the deck bar and a header per column; each column's body is a placeholder that a real site tab\n// webview (its own account profile) covers, laid out by state.ts. Paging, not pixel scrolling: a\n// page holds as many whole columns as fit; the others are parked off-page. Every request and every\n// action in a column is the site's own; the shell only navigates, focuses and configures columns\n// (native `column_configure`). The kinds of columns are the site's (`site.deck`).\n\nimport type { IDockviewPanelProps } from 'dockview';\nimport { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type MouseEvent as ReactMouseEvent, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { COLUMN_GAP, COLUMN_WIDTHS, isSourcePage, layoutColumns, pageOf, unreadTotal } from '../deckModel.ts';\nimport { tabProfile } from '../profileModel.ts';\nimport { AccountAvatar, accountName } from './AccountSwitcher.tsx';\nimport { AddColumnDialog } from './AddColumnDialog.tsx';\nimport { invoke } from './bridge.ts';\nimport {\n addColumn, bump, columnSourceUrl, configureColumn, deckById, decks, patchColumn, removeColumn, shiftColumn,\n type Deck, type DeckColumn,\n} from './deckStore.ts';\nimport { FindBar } from './FindBar.tsx';\nimport { useDecks, useProfiles, useT } from './hooks.ts';\nimport { Icon, type IconName } from './icons.tsx';\nimport { site } from './site.ts';\nimport { scheduleSync, setOverlay, shell, tabAction, type DeckParams } from './state.ts';\nimport { useTabStill } from './tabStill.ts';\nimport './deck.css';\n\nconst emitDecks = () => window.dispatchEvent(new CustomEvent('bt-decks'));\nconst unreadLabel = (count: number) => (count > 999 ? '999+' : String(count));\nconst deckSite = () => site().deck!;\n\n/** Width of the columns row minus an open compose dock. */\nfunction columnsWidth(total: number, deckId: string) {\n const compose = deckSite().compose;\n return compose && decks.compose.has(deckId) ? Math.max(0, total - compose.width - COLUMN_GAP) : total;\n}\n\n// ---------------------------------------------------------------------------------------------\n// Deck commands (keys, palette, column menus)\n\nexport type DeckCommand =\n | 'column-prev' | 'column-next' | 'column-page-prev' | 'column-page-next' | 'column-mark-read' | 'column-jump-unread' | 'deck-compose'\n | `column-${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`;\n\n/** The row width each deck was last laid out at (for paging from keys). */\nconst rowWidths = new Map<string, number>();\n\n/** Focuses a column: it becomes the deck's focused column, its page is shown and its webview gets the keys. */\nexport function focusColumn(deckId: string, columnId: string, giveKeys = true) {\n const deck = deckById(deckId);\n const column = deck?.columns.find(c => c.id === columnId);\n if (!deck || !column) return;\n decks.focus.set(deckId, columnId);\n const width = columnsWidth(rowWidths.get(deckId) ?? window.innerWidth, deckId);\n decks.page.set(deckId, pageOf(width, deck.columns, columnId, { maxVisible: decks.settings.maxVisible }, decks.page.get(deckId)));\n emitDecks();\n scheduleSync();\n if (giveKeys) requestAnimationFrame(() => tabAction(column.tabId, 'focus'));\n}\n\nexport function runDeckCommand(deckId: string, command: string) {\n const deck = deckById(deckId);\n if (!deck) return;\n const focused = deck.columns.find(c => c.id === decks.focus.get(deckId)) ?? deck.columns[0];\n const index = focused ? deck.columns.indexOf(focused) : -1;\n const digit = /^column-([1-9])$/.exec(command);\n if (digit) { const target = deck.columns[Number(digit[1]) - 1]; if (target) focusColumn(deckId, target.id); return; }\n switch (command) {\n case 'column-prev': case 'column-next': {\n const target = deck.columns[Math.min(deck.columns.length - 1, Math.max(0, index + (command === 'column-next' ? 1 : -1)))];\n if (target) focusColumn(deckId, target.id);\n break;\n }\n case 'column-page-prev': case 'column-page-next': {\n const width = columnsWidth(rowWidths.get(deckId) ?? window.innerWidth, deckId);\n const layout = layoutColumns(width, deck.columns, (decks.page.get(deckId) ?? 0) + (command === 'column-page-next' ? 1 : -1), { maxVisible: decks.settings.maxVisible });\n decks.page.set(deckId, layout.page);\n const first = layout.visible[0];\n if (first) decks.focus.set(deckId, first.id);\n emitDecks();\n scheduleSync();\n break;\n }\n case 'column-mark-read': if (focused) bump(focused, 'read'); break;\n case 'column-jump-unread': if (focused) bump(focused, 'jump'); break;\n case 'deck-compose': toggleCompose(deckId, focused?.profile); break;\n }\n}\n\nexport function toggleCompose(deckId: string, profile?: string) {\n if (!deckSite().compose) return;\n if (decks.compose.has(deckId)) decks.compose.delete(deckId);\n else decks.compose.set(deckId, { profile: tabProfile(shell.profiles, profile ?? shell.profiles.active).id });\n emitDecks();\n scheduleSync();\n}\n\n// ---------------------------------------------------------------------------------------------\n// Popovers (the shell rises above the tab webviews, or hides them, while one is open)\n\nfunction Popover({ anchor, onClose, children, width = 260, label }: { anchor: DOMRect; onClose(): void; children: ReactNode; width?: number; label: string }) {\n useEffect(() => {\n setOverlay(1);\n const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') { event.stopPropagation(); onClose(); } };\n window.addEventListener('keydown', onKey, true);\n window.addEventListener('blur', onClose);\n return () => { setOverlay(-1); window.removeEventListener('keydown', onKey, true); window.removeEventListener('blur', onClose); };\n }, []);\n const left = Math.max(8, Math.min(anchor.right - width, window.innerWidth - width - 8));\n const style: CSSProperties = { top: anchor.bottom + 6, left, width };\n return createPortal(<div className=\"bt-menu-backdrop\" onMouseDown={onClose} onContextMenu={event => { event.preventDefault(); onClose(); }}>\n <div className=\"bt-menu bt-deck-pop bt-pop bt-pop--right\" role=\"dialog\" aria-label={label} style={style} onMouseDown={event => event.stopPropagation()}>{children}</div>\n </div>, document.body);\n}\n\nfunction FilterPopover({ deckId, column, anchor, onClose }: { deckId: string; column: DeckColumn; anchor: DOMRect; onClose(): void }) {\n const tr = useT();\n const [text, setText] = useState('');\n const input = useRef<HTMLInputElement>(null);\n useEffect(() => { input.current?.focus(); }, []);\n const filters = column.filters;\n const set = (patch: Partial<DeckColumn['filters']>) => patchColumn(deckId, column.id, { filters: { ...filters, ...patch } });\n const add = () => {\n const terms = text.split(/\\n|,(?![^/]*\\/[a-z]*$)/).map(t => t.trim()).filter(Boolean).filter(t => t.length <= 200);\n if (!terms.length) return;\n set({ terms: [...filters.terms, ...terms.filter(t => !filters.terms.includes(t))].slice(0, 32) });\n setText('');\n };\n const toggle = (key: 'hideReplies' | 'hideReposts' | 'mediaOnly', label: string, hint: string) =>\n <label className=\"bt-deck-check\"><input type=\"checkbox\" checked={filters[key]} onChange={event => set({ [key]: event.target.checked })}/>\n <span className=\"bt-deck-check-box\" aria-hidden=\"true\"><Icon name=\"check\"/></span><span className=\"bt-deck-check-text\"><strong>{label}</strong><small>{hint}</small></span></label>;\n return <Popover anchor={anchor} onClose={onClose} width={300} label={tr('wb.deck.filters.label')}>\n <div className=\"bt-deck-pop-head\"><Icon name=\"filter\"/><strong>{tr('wb.deck.filters')}</strong><span>{deckSite().title(column.source, column.title).title}</span></div>\n <div className=\"bt-deck-terms\">\n <input ref={input} className=\"bt-deck-input\" spellCheck={false} placeholder={tr('wb.deck.mutePlaceholder')} aria-label={tr('wb.deck.muteLabel')} value={text}\n onChange={event => setText(event.target.value)} onKeyDown={event => { if (event.key === 'Enter') { event.preventDefault(); add(); } }}/>\n {filters.terms.length > 0 && <div className=\"bt-deck-chips\">\n {filters.terms.map(term => <span key={term} className={`bt-deck-chip ${/^\\/.+\\/[imsu]*$/.test(term) ? 'is-regex' : ''}`}>\n <span>{term}</span><button type=\"button\" aria-label={tr('wb.common.removeItem', { item: term })} onClick={() => set({ terms: filters.terms.filter(t => t !== term) })}><Icon name=\"close\"/></button></span>)}\n </div>}\n </div>\n <hr/>\n {toggle('hideReplies', tr('wb.deck.hideReplies'), tr('wb.deck.hideRepliesHint'))}\n {toggle('hideReposts', tr('wb.deck.hideReposts'), tr('wb.deck.hideRepostsHint'))}\n {toggle('mediaOnly', tr('wb.deck.mediaOnly'), tr('wb.deck.mediaOnlyHint'))}\n </Popover>;\n}\n\nfunction ColumnMenu({ deck, column, anchor, onClose, onRemove }: { deck: Deck; column: DeckColumn; anchor: DOMRect; onClose(): void; onRemove(): void }) {\n const tr = useT();\n const index = deck.columns.indexOf(column);\n const item = (label: string, icon: IconName, action: () => void, disabled = false, keys?: string) =>\n <button role=\"menuitem\" disabled={disabled} onClick={() => { onClose(); action(); }}>\n <Icon name={icon}/><span className=\"bt-menu-label\">{label}</span>{keys && <span className=\"bt-menu-keys\">{keys}</span>}</button>;\n const url = decks.runtime.get(column.tabId)?.url ?? columnSourceUrl(column.source) ?? '';\n return <Popover anchor={anchor} onClose={onClose} width={236} label={tr('wb.deck.menu')}>\n {item(tr('wb.deck.markRead'), 'check', () => bump(column, 'read'), false, 'Alt R')}\n {item(tr('wb.deck.jumpUnread'), 'history', () => bump(column, 'jump'), false, 'Alt U')}\n <hr/>\n {item(tr('wb.deck.moveLeft'), 'back', () => shiftColumn(deck.id, column.id, -1), index <= 0)}\n {item(tr('wb.deck.moveRight'), 'forward', () => shiftColumn(deck.id, column.id, 1), index >= deck.columns.length - 1)}\n <div className=\"bt-deck-widths\" role=\"group\" aria-label={tr('wb.deck.widthLabel')}>\n <span>{tr('wb.deck.width')}</span>\n {COLUMN_WIDTHS.map(width => <button key={width} type=\"button\" aria-pressed={column.width === width} className={column.width === width ? 'is-on' : ''}\n onClick={() => { patchColumn(deck.id, column.id, { width }); scheduleSync(); }}>{width}</button>)}\n </div>\n <hr/>\n {item(tr('wb.shell.menu.duplicate'), 'duplicate', () => addColumn(deck.id, { profile: column.profile, source: column.source, filters: column.filters, flags: column.flags, width: column.width }, column.id))}\n {item(tr('wb.deck.openAsTab'), 'external', () => shell.openUrl(url, column.profile), !url)}\n <hr/>\n {item(tr('wb.deck.remove'), 'trash', onRemove)}\n </Popover>;\n}\n\n// ---------------------------------------------------------------------------------------------\n// One column: header strip + the placeholder its webview covers\n\nfunction ColumnView({ deck, column, x, width, focused, number }: { deck: Deck; column: DeckColumn; x: number; width: number; focused: boolean; number: number }) {\n const tr = useT();\n const profiles = useProfiles();\n const body = useRef<HTMLDivElement>(null);\n const still = useTabStill(column.tabId);\n const [menu, setMenu] = useState<null | { kind: 'filters' | 'menu'; anchor: DOMRect }>(null);\n const [leaving, setLeaving] = useState(false);\n // Find in page for this column (Ctrl+F pressed in it): the find bar lies over the column's header.\n const [finding, setFinding] = useState(false);\n useEffect(() => {\n const openFindBar = (event: Event) => { if ((event as CustomEvent<string>).detail === column.tabId) setFinding(true); };\n window.addEventListener('bt-find', openFindBar);\n return () => window.removeEventListener('bt-find', openFindBar);\n }, [column.tabId]);\n const spec = deckSite();\n const runtime = decks.runtime.get(column.tabId);\n const account = tabProfile(profiles, column.profile);\n const type = spec.kinds.find(kind => kind.kind === column.source.kind);\n const { title, detail } = spec.title(column.source, column.title);\n const source = columnSourceUrl(column.source);\n const away = !!(runtime?.url && source && !isSourcePage(runtime.url, source));\n const unread = runtime?.unread ?? 0;\n const filtered = column.filters.terms.length > 0 || column.filters.hideReplies || column.filters.hideReposts || column.filters.mediaOnly;\n const pageTitle = spec.pageTitle ?? ((text: string) => text);\n\n useLayoutEffect(() => {\n const el = body.current;\n if (!el || leaving) return;\n shell.placeholders.set(column.tabId, el);\n const observer = new ResizeObserver(scheduleSync);\n observer.observe(el);\n scheduleSync();\n return () => {\n observer.disconnect();\n if (shell.placeholders.get(column.tabId) === el) shell.placeholders.delete(column.tabId);\n scheduleSync();\n };\n }, [column.tabId, leaving]);\n // Position changes (paging, reordering, width) move the webview with the placeholder.\n useEffect(() => { scheduleSync(); }, [x, width]);\n\n const open = (kind: 'filters' | 'menu') => (event: ReactMouseEvent<HTMLButtonElement>) =>\n setMenu(menu?.kind === kind ? null : { kind, anchor: event.currentTarget.getBoundingClientRect() });\n const remove = () => {\n setLeaving(true);\n // The webview hides at once (no placeholder); the header slides out, then the column goes.\n const reduced = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;\n setTimeout(() => removeColumn(deck.id, column.id), reduced ? 0 : 180);\n };\n\n return <section className={`bt-col${focused ? ' is-focused' : ''}${leaving ? ' is-leaving' : ''}`} style={{ left: x, width, ['--bt-col-account' as string]: account.color }}\n aria-label={tr('wb.deck.columnLabel', { title })} onMouseDown={() => { if (!focused) focusColumn(deck.id, column.id, false); }}>\n <header className=\"bt-col-head\">\n {away\n ? <button className=\"bt-col-glyph bt-col-back\" title={tr('wb.deck.backTo', { title })} aria-label={tr('wb.deck.backTo', { title })}\n onClick={() => { if (source) invoke('tab_navigate', { id: column.tabId, url: source }).catch(() => {}); }}><Icon name=\"back\"/></button>\n : <span className=\"bt-col-glyph\" aria-hidden=\"true\"><Icon name={type?.icon ?? 'globe'}/></span>}\n <div className=\"bt-col-titles\" title={detail ? `${title} · ${detail}` : title}>\n <strong>{title}</strong>\n <span>{away ? (pageTitle(runtime?.title ?? '') || tr('wb.deck.viewingPost')) : detail ?? `${site().accounts.handlePrefix}${account.account?.handle ?? account.name}`}</span>\n </div>\n {unread > 0 && <button className=\"bt-col-unread\" title={tr('wb.deck.jumpUnreadTitle')} aria-label={tr('wb.deck.unreadLabel', { count: unread })} onClick={() => bump(column, 'jump')}>{unreadLabel(unread)}</button>}\n <span className=\"bt-col-fill\"/>\n <span className=\"bt-col-account\" title={tr('wb.shell.tab.account', { name: accountName(account) })}><AccountAvatar profile={account} size={20}/></span>\n <button className={`bt-icon bt-col-btn${filtered ? ' is-active' : ''}`} title={tr('wb.deck.filters')} aria-label={tr('wb.deck.filters')} aria-haspopup=\"dialog\" aria-expanded={menu?.kind === 'filters'} onClick={open('filters')}><Icon name=\"filter\"/></button>\n <button className=\"bt-icon bt-col-btn\" title={tr('wb.deck.menu')} aria-label={tr('wb.deck.menu')} aria-haspopup=\"menu\" aria-expanded={menu?.kind === 'menu'} onClick={open('menu')}>\n <svg className=\"bt-glyph\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M6 12h.01M12 12h.01M18 12h.01\" strokeWidth=\"3\"/></svg></button>\n {number <= 9 && <span className=\"bt-col-key\" aria-hidden=\"true\">{number}</span>}\n {runtime?.loading && <span className=\"bt-col-progress\" aria-label={tr('wb.common.loading')}/>}\n {finding && <div className=\"bt-col-find\"><FindBar tabId={column.tabId} url={runtime?.url ?? source ?? ''} onClose={() => setFinding(false)}/></div>}\n </header>\n <div className=\"bt-col-body\" ref={body}>\n {still\n ? <div className=\"bt-still\" aria-hidden=\"true\" style={{ backgroundImage: `url(\"${still}\")` }}/>\n : <div className=\"bt-col-hint\"><span className=\"bt-spinner\" aria-hidden=\"true\"/><span>{title}</span></div>}\n </div>\n {menu?.kind === 'filters' && <FilterPopover deckId={deck.id} column={column} anchor={menu.anchor} onClose={() => setMenu(null)}/>}\n {menu?.kind === 'menu' && <ColumnMenu deck={deck} column={column} anchor={menu.anchor} onClose={() => setMenu(null)} onRemove={remove}/>}\n </section>;\n}\n\n// ---------------------------------------------------------------------------------------------\n\nfunction EmptyDeck({ deck, onAdd }: { deck: Deck; onAdd(): void }) {\n const tr = useT();\n const profiles = useProfiles();\n const ids = profiles.profiles.map(p => p.id);\n const ordered = [profiles.active, ...ids.filter(id => id !== profiles.active)];\n return <div className=\"bt-deck-empty bt-rise\">\n <div className=\"bt-deck-empty-art\" aria-hidden=\"true\">{[0, 1, 2, 3].map(i => <span key={i} style={{ animationDelay: `${i * 70}ms` }}/>)}</div>\n <h2>{tr('wb.deck.title')}</h2>\n <p>{tr('wb.deck.emptyHint', { site: site().name })}</p>\n <div className=\"bt-deck-empty-actions\">\n <button className=\"bt-deck-primary\" onClick={onAdd}><Icon name=\"plus\"/>{tr('wb.deck.addColumn')}</button>\n {(deckSite().presets ?? []).map(preset => {\n const needs = preset.needsTwoAccounts && ids.length < 2 ? preset.needsTwoAccounts() : undefined;\n return <button key={preset.id} className=\"bt-deck-secondary\" disabled={!!needs} title={needs}\n onClick={() => { for (const column of preset.columns(ordered)) addColumn(deck.id, column); }}>{preset.label()}</button>;\n })}\n </div>\n <p className=\"bt-deck-empty-keys\">\n <span><span className=\"bt-kbd\">[</span><span className=\"bt-kbd\">]</span> {tr('wb.deck.key.columns')}</span>\n <span><span className=\"bt-kbd\">Alt</span><span className=\"bt-kbd\">1–9</span> {tr('wb.deck.key.jump')}</span>\n <span><span className=\"bt-kbd\">Alt</span><span className=\"bt-kbd\">R</span> {tr('wb.deck.key.read')}</span>\n {deckSite().compose && <span><span className=\"bt-kbd\">Ctrl</span><span className=\"bt-kbd\">Alt</span><span className=\"bt-kbd\">N</span> {tr('wb.deck.key.post')}</span>}\n </p>\n </div>;\n}\n\nexport function DeckView(props: IDockviewPanelProps<DeckParams>) {\n const tr = useT();\n useDecks();\n const deckId = props.params.deckId;\n const row = useRef<HTMLDivElement>(null);\n const [rowWidth, setRowWidth] = useState(0);\n const [adding, setAdding] = useState(false);\n const deck = deckById(deckId);\n const compose = deckSite().compose;\n\n useLayoutEffect(() => {\n const el = row.current;\n if (!el) return;\n const measure = () => { const w = Math.floor(el.getBoundingClientRect().width); rowWidths.set(deckId, w); setRowWidth(w); };\n const observer = new ResizeObserver(measure);\n observer.observe(el);\n measure();\n return () => observer.disconnect();\n }, [deckId, !!deck]);\n useEffect(() => {\n const visibility = props.api.onDidVisibilityChange(scheduleSync);\n // The palette's \"Add column…\" opens this deck's dialog.\n const add = (event: Event) => { if ((event as CustomEvent<string>).detail === deckId) setAdding(true); };\n window.addEventListener('bt-deck-add', add);\n return () => { visibility.dispose(); window.removeEventListener('bt-deck-add', add); };\n }, [props.api, deckId]);\n // Every column gets its config before its webview exists (no flash of the site's chrome);\n // unmounting the deck forgets what was sent, so reopening it configures again.\n useEffect(() => {\n if (!deck) return;\n for (const column of deck.columns) {\n if (decks.sent.has(column.tabId)) continue;\n void configureColumn(column, true).then(() => { decks.ready.add(column.tabId); scheduleSync(); });\n }\n });\n useEffect(() => () => {\n for (const column of deckById(deckId)?.columns ?? []) { decks.sent.delete(column.tabId); decks.ready.delete(column.tabId); }\n }, [deckId]);\n\n if (!deck) {\n return <div className=\"bt-deck\"><div className=\"bt-deck-empty\"><h2>{tr('wb.deck.gone')}</h2><p>{tr('wb.deck.goneHint')}</p>\n <button className=\"bt-deck-secondary\" onClick={() => props.api.close()}>{tr('wb.shell.menu.close')}</button></div></div>;\n }\n const settings = decks.settings;\n const width = columnsWidth(rowWidth, deck.id);\n const layout = layoutColumns(width, deck.columns, decks.page.get(deck.id) ?? 0, { maxVisible: settings.maxVisible });\n const focusedId = decks.focus.get(deck.id) ?? layout.visible[0]?.id;\n const total = unreadTotal(new Map(deck.columns.map(c => [c.tabId, decks.runtime.get(c.tabId)?.unread ?? 0])), deck.columns);\n const setPage = (page: number) => { decks.page.set(deck.id, page); emitDecks(); scheduleSync(); };\n const composing = compose && decks.compose.get(deck.id);\n const overLimit = deck.columns.length > settings.maxVisible;\n\n return <div className=\"bt-deck\">\n <div className=\"bt-deck-bar\">\n <span className=\"bt-deck-mark\" aria-hidden=\"true\"><Icon name=\"grid\"/></span>\n <strong className=\"bt-deck-name\">{deck.name}</strong>\n <span className=\"bt-deck-count\">{tr('wb.deck.columnCount', { count: deck.columns.length })}</span>\n {total > 0 && <span className=\"bt-deck-total\" title={tr('wb.deck.unreadTitle')}>{tr('wb.deck.newCount', { count: unreadLabel(total) })}</span>}\n <span className=\"bt-deck-fill\"/>\n {layout.pages > 1 && <div className=\"bt-deck-pager\" role=\"group\" aria-label={tr('wb.deck.pages')}>\n <button className=\"bt-icon\" title={tr('wb.deck.prevTitle')} aria-label={tr('wb.deck.prev')} disabled={layout.page === 0} onClick={() => setPage(layout.page - 1)}><Icon name=\"back\"/></button>\n {Array.from({ length: layout.pages }, (_, i) => <button key={i} className={`bt-deck-dot${i === layout.page ? ' is-on' : ''}`} aria-label={tr('wb.deck.page', { n: i + 1 })} aria-current={i === layout.page ? 'page' : undefined} onClick={() => setPage(i)}/>)}\n <button className=\"bt-icon\" title={tr('wb.deck.nextTitle')} aria-label={tr('wb.deck.next')} disabled={layout.page >= layout.pages - 1} onClick={() => setPage(layout.page + 1)}><Icon name=\"forward\"/></button>\n </div>}\n {overLimit && <span className=\"bt-deck-memory\" title={tr('wb.deck.memoryTitle', { count: decks.settings.maxVisible, site: site().name })}>{tr('wb.deck.onScreen', { visible: layout.visible.length, total: deck.columns.length })}</span>}\n <button className=\"bt-deck-action\" onClick={() => setAdding(true)} title={tr('wb.deck.addColumn')}><Icon name=\"plus\"/><span>{tr('wb.deck.column')}</span></button>\n {compose && <button className={`bt-deck-action${composing ? ' is-on' : ''}`} onClick={() => toggleCompose(deck.id, deck.columns.find(c => c.id === focusedId)?.profile)} title={tr('wb.deck.postTitle')} aria-pressed={!!composing}>\n <Icon name=\"edit\"/><span>{tr('wb.deck.post')}</span></button>}\n <button className=\"bt-icon bt-deck-settings\" title={tr('wb.deck.settings')} aria-label={tr('wb.deck.settings')} onClick={() => shell.openPanelSection('power')}><Icon name=\"settings\"/></button>\n </div>\n <div className=\"bt-deck-row\" ref={row}>\n {deck.columns.length === 0\n ? <EmptyDeck deck={deck} onAdd={() => setAdding(true)}/>\n : layout.visible.map(place => {\n const column = deck.columns.find(c => c.id === place.id)!;\n return <ColumnView key={column.id} deck={deck} column={column} x={place.x} width={place.width} focused={column.id === focusedId}\n number={deck.columns.indexOf(column) + 1}/>;\n })}\n {compose && composing && <compose.Dock deckId={deck.id} left={width + COLUMN_GAP}/>}\n </div>\n {adding && <AddColumnDialog deck={deck} onClose={() => setAdding(false)} onAdd={input => {\n const column = addColumn(deck.id, input);\n void configureColumn(column, true).then(() => { decks.ready.add(column.tabId); focusColumn(deck.id, column.id, false); });\n setAdding(false);\n }}/>}\n </div>;\n}\n\n/** Unread total of a deck on its dockview tab. */\nexport function DeckTabBadge({ deckId }: { deckId: string }) {\n useDecks();\n const deck = deckById(deckId);\n if (!deck) return null;\n const total = unreadTotal(new Map(deck.columns.map(c => [c.tabId, decks.runtime.get(c.tabId)?.unread ?? 0])), deck.columns);\n return total > 0 ? <span className=\"bt-tab-unread\" aria-label={`${total} unread`}>{unreadLabel(total)}</span> : null;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import './findBar.css';
|
|
2
|
+
/** Opens (or focuses) the find bar of web tab `id`. */
|
|
3
|
+
export declare const openFind: (id: string) => boolean;
|
|
4
|
+
/** The next (`1`) or previous (`-1`) match in tab `id`, when its find bar is open (F3 anywhere in the shell). */
|
|
5
|
+
export declare const stepFind: (id: string, direction: 1 | -1) => boolean;
|
|
6
|
+
export declare function FindBar({ tabId, url, onClose }: {
|
|
7
|
+
tabId: string;
|
|
8
|
+
url: string;
|
|
9
|
+
onClose(): void;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Find in page: the shell's find bar for one pane. It takes the address field's place in that
|
|
3
|
+
// pane's toolbar while it is open (so the page under it does not move and, in split view, the bar
|
|
4
|
+
// is plainly the searched pane's). Native code does the searching (`tab_find`, shell-only): the
|
|
5
|
+
// engine's own find where the build can drive it (WebView2: highlights and a match count, which
|
|
6
|
+
// arrive as `tab-find` events), else the engine's `window.find` evaluated by native code (next and
|
|
7
|
+
// previous work, no count). Only what the page has rendered can be found, as in a browser: a
|
|
8
|
+
// virtualized list (X's timeline) holds the posts near the viewport, not the whole feed.
|
|
9
|
+
//
|
|
10
|
+
// The query lives in this component's state while the bar is open and nowhere else: it is not
|
|
11
|
+
// saved, logged or put in a URL, and closing the bar clears the engine's highlights.
|
|
12
|
+
// Keys: Enter / F3 next, Shift+Enter / Shift+F3 previous, Esc closes and gives the page the focus.
|
|
13
|
+
import { useEffect, useRef, useState } from 'react';
|
|
14
|
+
import { invoke, listen } from "./bridge.js";
|
|
15
|
+
import { describe, diag } from "./diag.js";
|
|
16
|
+
import { useT } from "./hooks.js";
|
|
17
|
+
import { formatNumber } from "./i18n.js";
|
|
18
|
+
import { Icon } from "./icons.js";
|
|
19
|
+
import { findLabel, menuText } from "./menuModel.js";
|
|
20
|
+
import { tabAction } from "./state.js";
|
|
21
|
+
import './findBar.css';
|
|
22
|
+
/** Opens (or focuses) the find bar of web tab `id`. */
|
|
23
|
+
export const openFind = (id) => window.dispatchEvent(new CustomEvent('bt-find', { detail: id }));
|
|
24
|
+
/** The next (`1`) or previous (`-1`) match in tab `id`, when its find bar is open (F3 anywhere in the shell). */
|
|
25
|
+
export const stepFind = (id, direction) => window.dispatchEvent(new CustomEvent('bt-find-step', { detail: { id, direction } }));
|
|
26
|
+
const find = (id, action, query) => invoke('tab_find', { id, action, ...(query ? { query } : {}) }).catch(() => { });
|
|
27
|
+
export function FindBar({ tabId, url, onClose }) {
|
|
28
|
+
useT();
|
|
29
|
+
const [query, setQuery] = useState('');
|
|
30
|
+
// What the engine reported for the query on screen (null: nothing yet, or an engine that does not count).
|
|
31
|
+
const [counts, setCounts] = useState(null);
|
|
32
|
+
const input = useRef(null);
|
|
33
|
+
const live = useRef(query);
|
|
34
|
+
live.current = query;
|
|
35
|
+
const close = () => {
|
|
36
|
+
onClose();
|
|
37
|
+
// The page gets the keyboard back.
|
|
38
|
+
void tabAction(tabId, 'focus');
|
|
39
|
+
};
|
|
40
|
+
const step = (direction) => { if (live.current)
|
|
41
|
+
void find(tabId, direction > 0 ? 'next' : 'previous', live.current); };
|
|
42
|
+
// The shell takes the keyboard (Ctrl+F was pressed in the page); closing clears the highlights.
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const focusField = () => { if (input.current && document.activeElement !== input.current)
|
|
45
|
+
input.current.focus(); };
|
|
46
|
+
invoke('shell_focus').then(focusField, () => { });
|
|
47
|
+
focusField();
|
|
48
|
+
diag(`find bar open: hasFocus=${document.hasFocus()} active=${describe(document.activeElement)}`);
|
|
49
|
+
// The page may keep the keyboard (the keys that opened the bar were pressed in it): if the shell
|
|
50
|
+
// still does not have it a moment later, ask once more, so typing never lands in the page.
|
|
51
|
+
const retry = setTimeout(() => {
|
|
52
|
+
diag(`find bar +250ms: hasFocus=${document.hasFocus()} active=${describe(document.activeElement)}`);
|
|
53
|
+
if (!document.hasFocus())
|
|
54
|
+
invoke('shell_focus').then(() => { focusField(); diag(`find bar refocused: hasFocus=${document.hasFocus()}`); }, () => { });
|
|
55
|
+
else
|
|
56
|
+
focusField();
|
|
57
|
+
}, 250);
|
|
58
|
+
const again = (event) => { if (event.detail === tabId) {
|
|
59
|
+
input.current?.focus();
|
|
60
|
+
input.current?.select();
|
|
61
|
+
} };
|
|
62
|
+
const onStep = (event) => { const detail = event.detail; if (detail.id === tabId)
|
|
63
|
+
step(detail.direction); };
|
|
64
|
+
window.addEventListener('bt-find', again);
|
|
65
|
+
window.addEventListener('bt-find-step', onStep);
|
|
66
|
+
let disposed = false;
|
|
67
|
+
let unlisten;
|
|
68
|
+
listen('tab-find', ({ payload }) => {
|
|
69
|
+
if (payload.id === tabId && live.current)
|
|
70
|
+
setCounts({ count: payload.count, index: payload.index });
|
|
71
|
+
}).then(dispose => { if (disposed)
|
|
72
|
+
dispose();
|
|
73
|
+
else
|
|
74
|
+
unlisten = dispose; }).catch(() => { });
|
|
75
|
+
return () => {
|
|
76
|
+
disposed = true;
|
|
77
|
+
clearTimeout(retry);
|
|
78
|
+
unlisten?.();
|
|
79
|
+
window.removeEventListener('bt-find', again);
|
|
80
|
+
window.removeEventListener('bt-find-step', onStep);
|
|
81
|
+
void find(tabId, 'stop');
|
|
82
|
+
};
|
|
83
|
+
}, [tabId]);
|
|
84
|
+
// A new query (or a new page under the same query) starts a new search, a beat after the last key.
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
setCounts(null);
|
|
87
|
+
if (!query) {
|
|
88
|
+
void find(tabId, 'stop');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const timer = setTimeout(() => void find(tabId, 'start', query), 140);
|
|
92
|
+
return () => clearTimeout(timer);
|
|
93
|
+
}, [query, url, tabId]);
|
|
94
|
+
const status = query && counts ? findLabel(counts, value => formatNumber(value)) : '';
|
|
95
|
+
return _jsxs("div", { className: `bt-omni bt-omni--edit bt-find${query && counts?.count === 0 ? ' is-none' : ''}`, role: "search", title: menuText('findHint'), children: [_jsx(Icon, { name: "search", className: "bt-omni-lead" }), _jsx("input", { ref: input, type: "text", spellCheck: false, autoComplete: "off", maxLength: 256, value: query, placeholder: menuText('findField'), "aria-label": menuText('findField'), onChange: event => setQuery(event.target.value.replace(/[\u0000-\u001f\u007f]/g, '')), onKeyDown: event => {
|
|
96
|
+
if (event.key === 'Enter' || event.key === 'F3') {
|
|
97
|
+
event.preventDefault();
|
|
98
|
+
event.stopPropagation();
|
|
99
|
+
step(event.shiftKey ? -1 : 1);
|
|
100
|
+
}
|
|
101
|
+
if (event.key === 'Escape') {
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
event.stopPropagation();
|
|
104
|
+
close();
|
|
105
|
+
}
|
|
106
|
+
} }), _jsx("span", { className: "bt-find-count", role: "status", "aria-live": "polite", children: status }), _jsx("button", { type: "button", className: "bt-omni-action", disabled: !query, title: `${menuText('findPrevious')} (Shift+Enter)`, "aria-label": menuText('findPrevious'), onMouseDown: event => event.preventDefault(), onClick: () => step(-1), children: _jsx(Icon, { name: "chevron", className: "bt-find-up" }) }), _jsx("button", { type: "button", className: "bt-omni-action", disabled: !query, title: `${menuText('findNext')} (Enter)`, "aria-label": menuText('findNext'), onMouseDown: event => event.preventDefault(), onClick: () => step(1), children: _jsx(Icon, { name: "chevron" }) }), _jsx("button", { type: "button", className: "bt-omni-action", title: `${menuText('findClose')} (Esc)`, "aria-label": menuText('findClose'), onClick: close, children: _jsx(Icon, { name: "close" }) })] });
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=FindBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FindBar.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/FindBar.tsx"],"names":[],"mappings":"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","sourcesContent":["// Find in page: the shell's find bar for one pane. It takes the address field's place in that\n// pane's toolbar while it is open (so the page under it does not move and, in split view, the bar\n// is plainly the searched pane's). Native code does the searching (`tab_find`, shell-only): the\n// engine's own find where the build can drive it (WebView2: highlights and a match count, which\n// arrive as `tab-find` events), else the engine's `window.find` evaluated by native code (next and\n// previous work, no count). Only what the page has rendered can be found, as in a browser: a\n// virtualized list (X's timeline) holds the posts near the viewport, not the whole feed.\n//\n// The query lives in this component's state while the bar is open and nowhere else: it is not\n// saved, logged or put in a URL, and closing the bar clears the engine's highlights.\n// Keys: Enter / F3 next, Shift+Enter / Shift+F3 previous, Esc closes and gives the page the focus.\n\nimport { useEffect, useRef, useState } from 'react';\nimport { invoke, listen } from './bridge.ts';\nimport { describe, diag } from './diag.ts';\nimport { useT } from './hooks.ts';\nimport { formatNumber } from './i18n.ts';\nimport { Icon } from './icons.tsx';\nimport { findLabel, menuText } from './menuModel.ts';\nimport { tabAction } from './state.ts';\nimport './findBar.css';\n\n/** Opens (or focuses) the find bar of web tab `id`. */\nexport const openFind = (id: string) => window.dispatchEvent(new CustomEvent('bt-find', { detail: id }));\n/** The next (`1`) or previous (`-1`) match in tab `id`, when its find bar is open (F3 anywhere in the shell). */\nexport const stepFind = (id: string, direction: 1 | -1) => window.dispatchEvent(new CustomEvent('bt-find-step', { detail: { id, direction } }));\n\nconst find = (id: string, action: 'start' | 'next' | 'previous' | 'stop', query?: string) =>\n invoke('tab_find', { id, action, ...(query ? { query } : {}) }).catch(() => {});\n\nexport function FindBar({ tabId, url, onClose }: { tabId: string; url: string; onClose(): void }) {\n useT();\n const [query, setQuery] = useState('');\n // What the engine reported for the query on screen (null: nothing yet, or an engine that does not count).\n const [counts, setCounts] = useState<{ count: number; index: number } | null>(null);\n const input = useRef<HTMLInputElement>(null);\n const live = useRef(query);\n live.current = query;\n\n const close = () => {\n onClose();\n // The page gets the keyboard back.\n void tabAction(tabId, 'focus');\n };\n const step = (direction: 1 | -1) => { if (live.current) void find(tabId, direction > 0 ? 'next' : 'previous', live.current); };\n\n // The shell takes the keyboard (Ctrl+F was pressed in the page); closing clears the highlights.\n useEffect(() => {\n const focusField = () => { if (input.current && document.activeElement !== input.current) input.current.focus(); };\n invoke('shell_focus').then(focusField, () => {});\n focusField();\n diag(`find bar open: hasFocus=${document.hasFocus()} active=${describe(document.activeElement)}`);\n // The page may keep the keyboard (the keys that opened the bar were pressed in it): if the shell\n // still does not have it a moment later, ask once more, so typing never lands in the page.\n const retry = setTimeout(() => {\n diag(`find bar +250ms: hasFocus=${document.hasFocus()} active=${describe(document.activeElement)}`);\n if (!document.hasFocus()) invoke('shell_focus').then(() => { focusField(); diag(`find bar refocused: hasFocus=${document.hasFocus()}`); }, () => {});\n else focusField();\n }, 250);\n const again = (event: Event) => { if ((event as CustomEvent<string>).detail === tabId) { input.current?.focus(); input.current?.select(); } };\n const onStep = (event: Event) => { const detail = (event as CustomEvent<{ id: string; direction: 1 | -1 }>).detail; if (detail.id === tabId) step(detail.direction); };\n window.addEventListener('bt-find', again);\n window.addEventListener('bt-find-step', onStep);\n let disposed = false;\n let unlisten: (() => void) | undefined;\n listen<{ id: string; count: number; index: number }>('tab-find', ({ payload }) => {\n if (payload.id === tabId && live.current) setCounts({ count: payload.count, index: payload.index });\n }).then(dispose => { if (disposed) dispose(); else unlisten = dispose; }).catch(() => {});\n return () => {\n disposed = true;\n clearTimeout(retry);\n unlisten?.();\n window.removeEventListener('bt-find', again);\n window.removeEventListener('bt-find-step', onStep);\n void find(tabId, 'stop');\n };\n }, [tabId]);\n\n // A new query (or a new page under the same query) starts a new search, a beat after the last key.\n useEffect(() => {\n setCounts(null);\n if (!query) { void find(tabId, 'stop'); return; }\n const timer = setTimeout(() => void find(tabId, 'start', query), 140);\n return () => clearTimeout(timer);\n }, [query, url, tabId]);\n\n const status = query && counts ? findLabel(counts, value => formatNumber(value)) : '';\n return <div className={`bt-omni bt-omni--edit bt-find${query && counts?.count === 0 ? ' is-none' : ''}`} role=\"search\" title={menuText('findHint')}>\n <Icon name=\"search\" className=\"bt-omni-lead\"/>\n <input ref={input} type=\"text\" spellCheck={false} autoComplete=\"off\" maxLength={256} value={query} placeholder={menuText('findField')} aria-label={menuText('findField')}\n onChange={event => setQuery(event.target.value.replace(/[\\u0000-\\u001f\\u007f]/g, ''))}\n onKeyDown={event => {\n if (event.key === 'Enter' || event.key === 'F3') { event.preventDefault(); event.stopPropagation(); step(event.shiftKey ? -1 : 1); }\n if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); close(); }\n }}/>\n <span className=\"bt-find-count\" role=\"status\" aria-live=\"polite\">{status}</span>\n <button type=\"button\" className=\"bt-omni-action\" disabled={!query} title={`${menuText('findPrevious')} (Shift+Enter)`} aria-label={menuText('findPrevious')}\n onMouseDown={event => event.preventDefault()} onClick={() => step(-1)}><Icon name=\"chevron\" className=\"bt-find-up\"/></button>\n <button type=\"button\" className=\"bt-omni-action\" disabled={!query} title={`${menuText('findNext')} (Enter)`} aria-label={menuText('findNext')}\n onMouseDown={event => event.preventDefault()} onClick={() => step(1)}><Icon name=\"chevron\"/></button>\n <button type=\"button\" className=\"bt-omni-action\" title={`${menuText('findClose')} (Esc)`} aria-label={menuText('findClose')} onClick={close}><Icon name=\"close\"/></button>\n </div>;\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media side panel: recent images from the owner's gallery folders and the local clipboard
|
|
3
|
+
* history. Choosing an item attaches the image to (or inserts the text into) the composer of the
|
|
4
|
+
* active site tab (`site.media.canAttach`). Nothing is posted; the user reviews and sends it themselves.
|
|
5
|
+
*/
|
|
6
|
+
export declare function MediaPanel({ onClose }: {
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
}): import("react").ReactPortal;
|