waybetter 0.1.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -6
- package/bin/waybetter.mjs +43 -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/release.mjs +437 -0
- package/cli/releasecheck.mjs +15 -0
- package/cli/remote.mjs +260 -0
- package/cli/store.mjs +378 -0
- package/cli/strings.mjs +123 -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 +61 -0
- package/dist/runtime/stringPackTranslate.js +267 -0
- package/dist/runtime/stringPackTranslate.js.map +1 -0
- package/dist/runtime/stringPacks.d.ts +248 -0
- package/dist/runtime/stringPacks.js +610 -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/themeBar.d.ts +28 -0
- package/dist/runtime/themeBar.js +82 -0
- package/dist/runtime/themeBar.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 +476 -0
- package/dist/runtime/themeComponents.js.map +1 -0
- package/dist/runtime/themeDecor.d.ts +73 -0
- package/dist/runtime/themeDecor.js +133 -0
- package/dist/runtime/themeDecor.js.map +1 -0
- package/dist/runtime/themeDerive.d.ts +69 -0
- package/dist/runtime/themeDerive.js +117 -0
- package/dist/runtime/themeDerive.js.map +1 -0
- package/dist/runtime/themeDoctor.d.ts +52 -0
- package/dist/runtime/themeDoctor.js +112 -0
- package/dist/runtime/themeDoctor.js.map +1 -0
- package/dist/runtime/themeGuards.d.ts +60 -0
- package/dist/runtime/themeGuards.js +235 -0
- package/dist/runtime/themeGuards.js.map +1 -0
- package/dist/runtime/themeIcons.d.ts +130 -0
- package/dist/runtime/themeIcons.js +271 -0
- package/dist/runtime/themeIcons.js.map +1 -0
- package/dist/runtime/themeInk.d.ts +37 -0
- package/dist/runtime/themeInk.js +111 -0
- package/dist/runtime/themeInk.js.map +1 -0
- package/dist/runtime/themeInvariants.d.ts +39 -0
- package/dist/runtime/themeInvariants.js +273 -0
- package/dist/runtime/themeInvariants.js.map +1 -0
- package/dist/runtime/themeRuntime.d.ts +114 -0
- package/dist/runtime/themeRuntime.js +570 -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 +263 -0
- package/dist/runtime/themeSpec.js +435 -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 +176 -0
- package/dist/shell/InstallDialog.js.map +1 -0
- package/dist/shell/StoreView.d.ts +78 -0
- package/dist/shell/StoreView.js +108 -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 +44 -0
- package/dist/shell/frame/AppMenu.js +721 -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 +9 -0
- package/dist/shell/frame/Shell.js +1139 -0
- package/dist/shell/frame/Shell.js.map +1 -0
- package/dist/shell/frame/Titlebar.d.ts +17 -0
- package/dist/shell/frame/Titlebar.js +79 -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 +185 -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 +127 -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 +37 -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 +47 -0
- package/dist/shell/frame/chromeTheme.js +118 -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/edges.css +159 -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 +47 -0
- package/dist/shell/frame/mediaModel.js +67 -0
- package/dist/shell/frame/mediaModel.js.map +1 -0
- package/dist/shell/frame/menuMessages.en.json +96 -0
- package/dist/shell/frame/menuModel.d.ts +319 -0
- package/dist/shell/frame/menuModel.js +301 -0
- package/dist/shell/frame/menuModel.js.map +1 -0
- package/dist/shell/frame/nativeMenu.d.ts +5 -0
- package/dist/shell/frame/nativeMenu.js +178 -0
- package/dist/shell/frame/nativeMenu.js.map +1 -0
- package/dist/shell/frame/nativeMenuModel.d.ts +102 -0
- package/dist/shell/frame/nativeMenuModel.js +186 -0
- package/dist/shell/frame/nativeMenuModel.js.map +1 -0
- package/dist/shell/frame/paletteModel.d.ts +139 -0
- package/dist/shell/frame/paletteModel.js +114 -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 +634 -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 +101 -0
- package/dist/shell/frame/state.js +286 -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 +267 -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 +137 -0
- package/dist/shell/installController.js +172 -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 +265 -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 +117 -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 +7 -0
- package/dist/shell/panel/StoreSection.js +78 -0
- package/dist/shell/panel/StoreSection.js.map +1 -0
- package/dist/shell/panel/StringPacks.d.ts +20 -0
- package/dist/shell/panel/StringPacks.js +131 -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 +240 -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 +73 -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 +803 -0
- package/dist/shell/panel/panelMessages.js +779 -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 +250 -0
- package/dist/shell/storeMessages.d.ts +193 -0
- package/dist/shell/storeMessages.js +196 -0
- package/dist/shell/storeMessages.js.map +1 -0
- package/dist/shell/storeModel.d.ts +205 -0
- package/dist/shell/storeModel.js +146 -0
- package/dist/shell/storeModel.js.map +1 -0
- package/dist/shell/stringPacksModel.d.ts +44 -0
- package/dist/shell/stringPacksModel.js +99 -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 +655 -0
- package/languages.schema.json +23 -0
- package/locales/ar-x-fm.json +11 -0
- package/locales/ar.json +1388 -0
- package/locales/bg.json +1387 -0
- package/locales/bn.json +1387 -0
- package/locales/ca.json +1387 -0
- package/locales/cs.json +1387 -0
- package/locales/da.json +1387 -0
- package/locales/de.json +1387 -0
- package/locales/el.json +1387 -0
- package/locales/en-GB.json +27 -0
- package/locales/en.json +1386 -0
- package/locales/en.meta.json +51 -0
- package/locales/es.json +1387 -0
- package/locales/eu.json +1387 -0
- package/locales/fa.json +1388 -0
- package/locales/fi.json +1387 -0
- package/locales/fil.json +1387 -0
- package/locales/fr.json +1387 -0
- package/locales/ga.json +1387 -0
- package/locales/gl.json +1387 -0
- package/locales/gu.json +1387 -0
- package/locales/ha.json +1387 -0
- package/locales/he.json +1388 -0
- package/locales/hi.json +1387 -0
- package/locales/hr.json +1387 -0
- package/locales/hu.json +1387 -0
- package/locales/id.json +1387 -0
- package/locales/ig.json +1387 -0
- package/locales/it.json +1387 -0
- package/locales/ja.json +1387 -0
- package/locales/kn.json +1387 -0
- package/locales/ko.json +1387 -0
- package/locales/mr.json +1387 -0
- package/locales/ms.json +1387 -0
- package/locales/nb.json +1387 -0
- package/locales/nl.json +1387 -0
- package/locales/pl.json +1387 -0
- package/locales/pt.json +1387 -0
- package/locales/ro.json +1387 -0
- package/locales/ru.json +1387 -0
- package/locales/sk.json +1387 -0
- package/locales/sr.json +1387 -0
- package/locales/sv.json +1387 -0
- package/locales/ta.json +1387 -0
- package/locales/th.json +1387 -0
- package/locales/tr.json +1387 -0
- package/locales/uk.json +1387 -0
- package/locales/ur.json +1388 -0
- package/locales/vi.json +1387 -0
- package/locales/yo.json +1387 -0
- package/locales/zh-Hans.json +1387 -0
- package/locales/zh-Hant.json +1387 -0
- package/package.json +138 -5
- package/store-catalog.schema.json +78 -0
- package/theme.schema.json +4668 -0
- package/windows/installer.nsi +946 -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
package/cli/strings.mjs
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// `waybetter strings check`: a string pack against a site's string inventory, with the
|
|
2
|
+
// framework's rules (waybetter/runtime/stringPacks: the envelope, only inventory keys, parameter
|
|
3
|
+
// names, plural and select kinds, no markup) and its coverage.
|
|
4
|
+
//
|
|
5
|
+
// waybetter strings check pack.strings.json --inventory strings/x.web.inventory.json
|
|
6
|
+
// waybetter strings check pack.strings.json the inventory comes from the config
|
|
7
|
+
// waybetter strings check pack.strings.json --verbose list every key that was refused or unknown
|
|
8
|
+
//
|
|
9
|
+
// Config: waybetter.strings.json in the app's root (or --config <file>); paths are relative to it.
|
|
10
|
+
//
|
|
11
|
+
// { "inventories": ["strings/x.web.inventory.json"] }
|
|
12
|
+
//
|
|
13
|
+
// The pack names its site and catalog; the inventory with the same two is used. Exit 1 when the
|
|
14
|
+
// envelope is invalid, a value is refused or a key is unknown (none of those is ever applied).
|
|
15
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
16
|
+
import { dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
17
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
18
|
+
|
|
19
|
+
export const STRINGS_CONFIG_FILE = 'waybetter.strings.json';
|
|
20
|
+
|
|
21
|
+
export const STRINGS_USAGE = `Usage:
|
|
22
|
+
waybetter strings check <pack> [--inventory <file>] [--verbose] [--config <file>]
|
|
23
|
+
Validates a string pack against the site's string inventory and prints its coverage.
|
|
24
|
+
|
|
25
|
+
Config: ${STRINGS_CONFIG_FILE} in the app's root (inventories).`;
|
|
26
|
+
|
|
27
|
+
class StringsError extends Error {}
|
|
28
|
+
|
|
29
|
+
const LISTED = 12;
|
|
30
|
+
|
|
31
|
+
/** The pack rules: the framework's sources inside its repository, else the built package. */
|
|
32
|
+
async function loadRules() {
|
|
33
|
+
const source = fileURLToPath(new URL('../../runtime/src/stringPacks.ts', import.meta.url));
|
|
34
|
+
const built = fileURLToPath(new URL('../dist/runtime/stringPacks.js', import.meta.url));
|
|
35
|
+
const file = existsSync(source) ? source : built;
|
|
36
|
+
if (!existsSync(file)) throw new StringsError('the string pack rules are not built (run the package build)');
|
|
37
|
+
return import(pathToFileURL(file).href);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readJson(file, what) {
|
|
41
|
+
if (!existsSync(file)) throw new StringsError(`${what} not found: ${file}`);
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(readFileSync(file, 'utf8'));
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new StringsError(`${what} is not JSON: ${file} (${error instanceof Error ? error.message : error})`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The inventories a config lists, as absolute paths. */
|
|
50
|
+
export function loadStringsConfig(cwd, file) {
|
|
51
|
+
const path = resolve(cwd, file ?? STRINGS_CONFIG_FILE);
|
|
52
|
+
if (!existsSync(path)) throw new StringsError(`${relative(cwd, path) || path} not found: pass --inventory <file> (see \`waybetter strings --help\`)`);
|
|
53
|
+
const config = readJson(path, 'the config');
|
|
54
|
+
if (!Array.isArray(config.inventories) || config.inventories.some(item => typeof item !== 'string')) throw new StringsError(`${relative(cwd, path)}: "inventories" must be a list of files`);
|
|
55
|
+
return { inventories: config.inventories.map(item => resolve(dirname(path), item)) };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const percent = (part, whole) => (whole ? `${(part / whole * 100).toFixed(part && part < whole / 1000 ? 2 : 1)}%` : 'n/a');
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Checks one pack. `inventories` are inventory files; the one for the pack's site and catalog is
|
|
62
|
+
* used. Returns the lines to print, the number of errors and the compiled report.
|
|
63
|
+
*/
|
|
64
|
+
export async function checkPack(packFile, inventories, { verbose = false } = {}) {
|
|
65
|
+
const rules = await loadRules();
|
|
66
|
+
const pack = readJson(packFile, 'the pack');
|
|
67
|
+
const lines = [];
|
|
68
|
+
const issues = rules.checkPackShape(pack);
|
|
69
|
+
for (const issue of issues) lines.push(`${issue.level}: ${issue.message}`);
|
|
70
|
+
if (issues.some(issue => issue.level === 'error')) return { lines, errors: issues.filter(issue => issue.level === 'error').length, report: null, coverage: null };
|
|
71
|
+
const loaded = inventories.map(file => ({ file, inventory: readJson(file, 'the inventory') }));
|
|
72
|
+
const match = loaded.find(item => item.inventory.site === pack.site && item.inventory.catalog === pack.catalog);
|
|
73
|
+
if (!match) throw new StringsError(`no inventory for ${pack.site}/${pack.catalog} (have: ${loaded.map(item => `${item.inventory.site}/${item.inventory.catalog}`).join(', ') || 'none'})`);
|
|
74
|
+
if (match.inventory.format !== 1 || typeof match.inventory.entries !== 'object') throw new StringsError(`${match.file} is not a string inventory`);
|
|
75
|
+
const compiled = rules.compilePack(pack, match.inventory);
|
|
76
|
+
const { report } = compiled;
|
|
77
|
+
const coverage = rules.coverage(match.inventory, compiled);
|
|
78
|
+
lines.push(`${pack.name} (${pack.language}) for ${pack.site}/${pack.catalog}, inventory build ${match.inventory.build ?? 'unknown'}`);
|
|
79
|
+
lines.push(`${report.total} strings: ${report.valid} valid, ${report.rejected.length} refused, ${report.unknown.length} unknown`);
|
|
80
|
+
if (pack.when?.languages) lines.push(`Applies only while the site shows: ${pack.when.languages.join(', ')}`);
|
|
81
|
+
if (pack.rewrite) lines.push(`Rewords ${Object.keys(pack.rewrite.words).length} words inside the site's own text: ${Object.keys(pack.rewrite.words).slice(0, 6).join(', ')}${Object.keys(pack.rewrite.words).length > 6 ? ', …' : ''}`);
|
|
82
|
+
const list = (items, render) => {
|
|
83
|
+
for (const item of verbose ? items : items.slice(0, LISTED)) lines.push(` ${render(item)}`);
|
|
84
|
+
if (!verbose && items.length > LISTED) lines.push(` … ${items.length - LISTED} more (--verbose lists all)`);
|
|
85
|
+
};
|
|
86
|
+
if (report.rejected.length) {
|
|
87
|
+
lines.push('Refused (not applied, the site\'s text stays):');
|
|
88
|
+
list(report.rejected, item => `${item.id}: ${item.reason}`);
|
|
89
|
+
}
|
|
90
|
+
if (report.unknown.length) {
|
|
91
|
+
lines.push('Unknown keys (not in the inventory, never applied):');
|
|
92
|
+
list(report.unknown, id => id);
|
|
93
|
+
}
|
|
94
|
+
lines.push('Coverage:');
|
|
95
|
+
for (const [group, numbers] of Object.entries(coverage)) {
|
|
96
|
+
lines.push(` ${group.padEnd(8)} ${numbers.translated} of ${numbers.translatable} translatable strings (${percent(numbers.translated, numbers.translatable)})${numbers.closed ? `; ${numbers.closed} not translatable yet (rich text, formatters)` : ''}`);
|
|
97
|
+
}
|
|
98
|
+
return { lines, errors: report.rejected.length + report.unknown.length, report, coverage };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function stringsCommand(args, { cwd = process.cwd(), log = console.log } = {}) {
|
|
102
|
+
const [action, ...rest] = args;
|
|
103
|
+
const value = flag => {
|
|
104
|
+
const at = rest.indexOf(flag);
|
|
105
|
+
if (at < 0) return undefined;
|
|
106
|
+
if (!rest[at + 1] || rest[at + 1].startsWith('--')) throw new StringsError(`${flag} needs a file`);
|
|
107
|
+
return rest[at + 1];
|
|
108
|
+
};
|
|
109
|
+
if (action === 'check') {
|
|
110
|
+
const inventory = value('--inventory');
|
|
111
|
+
const config = value('--config');
|
|
112
|
+
const taken = new Set([inventory, config].filter(Boolean));
|
|
113
|
+
const [pack, ...extra] = rest.filter(arg => !arg.startsWith('--') && !taken.has(arg));
|
|
114
|
+
if (!pack || extra.length) throw new StringsError('check needs one pack file');
|
|
115
|
+
const at = file => (isAbsolute(file) ? file : resolve(cwd, file));
|
|
116
|
+
const inventories = inventory ? [at(inventory)] : loadStringsConfig(cwd, config).inventories;
|
|
117
|
+
const result = await checkPack(at(pack), inventories, { verbose: rest.includes('--verbose') });
|
|
118
|
+
for (const line of result.lines) log(line);
|
|
119
|
+
return result.errors ? 1 : 0;
|
|
120
|
+
}
|
|
121
|
+
log(STRINGS_USAGE);
|
|
122
|
+
return action && action !== '--help' && action !== '-h' ? 1 : 0;
|
|
123
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export type ColumnDensity = 'compact' | 'comfortable';
|
|
2
|
+
export type ColumnFiltersConfig = {
|
|
3
|
+
terms: string[];
|
|
4
|
+
hideReplies: boolean;
|
|
5
|
+
hideReposts: boolean;
|
|
6
|
+
mediaOnly: boolean;
|
|
7
|
+
};
|
|
8
|
+
/** What native code delivers for one column (validated there too; see waybetter-host `ColumnConfig`). */
|
|
9
|
+
export type ColumnConfig = {
|
|
10
|
+
/** The column's own page (its source); chrome that only makes sense elsewhere hides only here. */
|
|
11
|
+
url: string;
|
|
12
|
+
density: ColumnDensity;
|
|
13
|
+
filters: ColumnFiltersConfig;
|
|
14
|
+
/** Count unread items and report them. */
|
|
15
|
+
unread: boolean;
|
|
16
|
+
/** Increments when the shell asks to mark everything read / jump to the first unread item. */
|
|
17
|
+
readSeq: number;
|
|
18
|
+
jumpSeq: number;
|
|
19
|
+
/** Source kind (adapter-defined), for `prepare`. */
|
|
20
|
+
kind: string;
|
|
21
|
+
};
|
|
22
|
+
export type ItemKind = {
|
|
23
|
+
reply: boolean;
|
|
24
|
+
repost: boolean;
|
|
25
|
+
media: boolean;
|
|
26
|
+
};
|
|
27
|
+
export type ColumnSite = {
|
|
28
|
+
/** Prefix of the attributes/ids this module owns (`data-<prefix>-column`, `<prefix>-column-css`). */
|
|
29
|
+
prefix: string;
|
|
30
|
+
/** The site's content column; it fills the column width. */
|
|
31
|
+
keep: string;
|
|
32
|
+
/** Always hidden in a column. */
|
|
33
|
+
hide: readonly string[];
|
|
34
|
+
/** Hidden only on the column's own page (e.g. a page title the column header repeats). */
|
|
35
|
+
sourceHide?: readonly string[];
|
|
36
|
+
/** Items for filters and the unread tracker. */
|
|
37
|
+
itemSelector: string;
|
|
38
|
+
/** The element hidden for a filtered item (default: the item itself). */
|
|
39
|
+
container?(item: Element): Element;
|
|
40
|
+
/** A stable id for an item (e.g. a post id), or null to ignore it. */
|
|
41
|
+
itemId(item: Element): string | null;
|
|
42
|
+
itemKind?(item: Element): ItemKind;
|
|
43
|
+
itemText?(item: Element): string;
|
|
44
|
+
/** Items the site announces but has not rendered yet (e.g. a "Show 12 posts" button); 0 = none. */
|
|
45
|
+
pendingCount?(doc: Document): number;
|
|
46
|
+
/** Site CSS for the column (density-aware); every rule should be scoped to `html[data-<prefix>-column]`. */
|
|
47
|
+
css?(density: ColumnDensity): string;
|
|
48
|
+
/** Navigation-only setup on the source page (e.g. select a timeline tab); true once done. */
|
|
49
|
+
prepare?(doc: Document, config: ColumnConfig): boolean;
|
|
50
|
+
};
|
|
51
|
+
export type ColumnHandle = {
|
|
52
|
+
set(config: unknown): void;
|
|
53
|
+
markRead(): void;
|
|
54
|
+
jumpToUnread(): void;
|
|
55
|
+
/** Current unread count (tracked + pending), 0 when off. */
|
|
56
|
+
unread(): number;
|
|
57
|
+
dispose(): void;
|
|
58
|
+
};
|
|
59
|
+
export type ColumnWindow = Window & typeof globalThis;
|
|
60
|
+
export declare function normalizeColumnConfig(value: unknown): ColumnConfig | null;
|
|
61
|
+
/** `/pattern/flags` → RegExp (flags i, m, s, u only); anything else is a plain keyword. Invalid → null. */
|
|
62
|
+
export declare function parseTerm(term: string): RegExp | string | null;
|
|
63
|
+
export type FilterInput = {
|
|
64
|
+
text: string;
|
|
65
|
+
} & ItemKind;
|
|
66
|
+
/** A predicate that says whether an item is hidden by the column's filters. */
|
|
67
|
+
export declare function compileFilters(filters: ColumnFiltersConfig): (item: FilterInput) => boolean;
|
|
68
|
+
/** Same page: origin, path (trailing slash ignored) and query. */
|
|
69
|
+
export declare function isSourcePage(href: string, source: string): boolean;
|
|
70
|
+
export type UnreadTracker = {
|
|
71
|
+
/**
|
|
72
|
+
* The rendered items, top to bottom, and which of them are on screen right now. The first
|
|
73
|
+
* non-empty observation is the baseline (read). Later, an id rendered above both the topmost
|
|
74
|
+
* read id and the topmost item on screen is unread (new, not seen yet); ids below are older
|
|
75
|
+
* items (read).
|
|
76
|
+
*/
|
|
77
|
+
observe(ordered: readonly string[], onScreen: ReadonlySet<string>): void;
|
|
78
|
+
/** An item came on screen. */
|
|
79
|
+
seen(id: string): void;
|
|
80
|
+
markRead(): void;
|
|
81
|
+
count(): number;
|
|
82
|
+
/** The unread item closest to the read ones (the next one to read, scrolling up), if rendered. */
|
|
83
|
+
nextUnread(ordered: readonly string[]): string | null;
|
|
84
|
+
isUnread(id: string): boolean;
|
|
85
|
+
};
|
|
86
|
+
export declare function createUnreadTracker(): UnreadTracker;
|
|
87
|
+
/** Pure: the module's stylesheet. Every rule is scoped to the column attribute on <html>. */
|
|
88
|
+
export declare function buildColumnCss(site: ColumnSite, density: ColumnDensity): string;
|
|
89
|
+
export type ColumnOptions = {
|
|
90
|
+
/** Called with the unread count (tracked + pending) whenever it changes, at most every 250 ms. */
|
|
91
|
+
onUnread?(count: number): void;
|
|
92
|
+
};
|
|
93
|
+
export declare function installColumnMode(win: ColumnWindow, site: ColumnSite, options?: ColumnOptions): ColumnHandle;
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
// Power User Mode, page side: a site tab that is a deck column (see shell/deckModel.ts). The shell
|
|
2
|
+
// lays the column out; native code hands this module the column's config. Here the page hides the
|
|
3
|
+
// site's chrome (rail, side column, floating buttons), lets the content column fill the width,
|
|
4
|
+
// applies the column's density and filters, and tracks unread items. It never makes a request and
|
|
5
|
+
// never clicks anything on its own except what the adapter's `prepare` does (navigation only, e.g.
|
|
6
|
+
// selecting one of the site's own timeline tabs). Unread items are counted from what the site has
|
|
7
|
+
// rendered: new item ids above the ones already seen, not yet scrolled into view. Only the count
|
|
8
|
+
// leaves the page (the adapter reports it through its own bridge).
|
|
9
|
+
import { watchDom } from "./domHub.js";
|
|
10
|
+
const MAX_TERMS = 32;
|
|
11
|
+
const MAX_TERM_CHARS = 200;
|
|
12
|
+
const MAX_IDS = 2000;
|
|
13
|
+
// ---------------------------------------------------------------------------------------------
|
|
14
|
+
// Config and filters (pure)
|
|
15
|
+
export function normalizeColumnConfig(value) {
|
|
16
|
+
if (!value || typeof value !== 'object')
|
|
17
|
+
return null;
|
|
18
|
+
const raw = value;
|
|
19
|
+
if (typeof raw.url !== 'string' || raw.url.length > 2048)
|
|
20
|
+
return null;
|
|
21
|
+
const filters = (raw.filters && typeof raw.filters === 'object' ? raw.filters : {});
|
|
22
|
+
const terms = (Array.isArray(filters.terms) ? filters.terms : [])
|
|
23
|
+
.filter((term) => typeof term === 'string' && term.trim().length > 0 && term.length <= MAX_TERM_CHARS)
|
|
24
|
+
.slice(0, MAX_TERMS);
|
|
25
|
+
const seq = (n) => (typeof n === 'number' && Number.isFinite(n) && n >= 0 ? Math.floor(n) : 0);
|
|
26
|
+
return {
|
|
27
|
+
url: raw.url,
|
|
28
|
+
density: raw.density === 'comfortable' ? 'comfortable' : 'compact',
|
|
29
|
+
filters: { terms, hideReplies: filters.hideReplies === true, hideReposts: filters.hideReposts === true, mediaOnly: filters.mediaOnly === true },
|
|
30
|
+
unread: raw.unread !== false,
|
|
31
|
+
readSeq: seq(raw.readSeq),
|
|
32
|
+
jumpSeq: seq(raw.jumpSeq),
|
|
33
|
+
kind: typeof raw.kind === 'string' && raw.kind.length <= 24 ? raw.kind : '',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** `/pattern/flags` → RegExp (flags i, m, s, u only); anything else is a plain keyword. Invalid → null. */
|
|
37
|
+
export function parseTerm(term) {
|
|
38
|
+
const text = term.trim();
|
|
39
|
+
if (!text)
|
|
40
|
+
return null;
|
|
41
|
+
const match = /^\/(.+)\/([imsu]*)$/.exec(text);
|
|
42
|
+
if (!match)
|
|
43
|
+
return text.toLowerCase();
|
|
44
|
+
try {
|
|
45
|
+
return new RegExp(match[1], match[2].includes('i') ? match[2] : `${match[2]}i`);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** A predicate that says whether an item is hidden by the column's filters. */
|
|
52
|
+
export function compileFilters(filters) {
|
|
53
|
+
const terms = filters.terms.map(parseTerm).filter((term) => term !== null);
|
|
54
|
+
const active = terms.length > 0 || filters.hideReplies || filters.hideReposts || filters.mediaOnly;
|
|
55
|
+
if (!active)
|
|
56
|
+
return () => false;
|
|
57
|
+
return item => {
|
|
58
|
+
if (filters.hideReplies && item.reply)
|
|
59
|
+
return true;
|
|
60
|
+
if (filters.hideReposts && item.repost)
|
|
61
|
+
return true;
|
|
62
|
+
if (filters.mediaOnly && !item.media)
|
|
63
|
+
return true;
|
|
64
|
+
if (!terms.length)
|
|
65
|
+
return false;
|
|
66
|
+
const lower = item.text.toLowerCase();
|
|
67
|
+
for (const term of terms) {
|
|
68
|
+
if (typeof term === 'string' ? lower.includes(term) : term.test(item.text))
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** Same page: origin, path (trailing slash ignored) and query. */
|
|
75
|
+
export function isSourcePage(href, source) {
|
|
76
|
+
try {
|
|
77
|
+
const a = new URL(href);
|
|
78
|
+
const b = new URL(source);
|
|
79
|
+
const path = (url) => url.pathname.replace(/\/+$/, '') || '/';
|
|
80
|
+
return a.origin === b.origin && path(a) === path(b) && a.search === b.search;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function createUnreadTracker() {
|
|
87
|
+
const read = new Set();
|
|
88
|
+
const unread = new Set();
|
|
89
|
+
let baseline = false;
|
|
90
|
+
const remember = (set, id) => {
|
|
91
|
+
set.add(id);
|
|
92
|
+
if (set.size > MAX_IDS)
|
|
93
|
+
set.delete(set.values().next().value);
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
observe(ordered, onScreen) {
|
|
97
|
+
if (!ordered.length)
|
|
98
|
+
return;
|
|
99
|
+
if (!baseline) {
|
|
100
|
+
baseline = true;
|
|
101
|
+
for (const id of ordered)
|
|
102
|
+
remember(read, id);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const topRead = ordered.findIndex(id => read.has(id));
|
|
106
|
+
const topShown = ordered.findIndex(id => onScreen.has(id));
|
|
107
|
+
const limit = topShown >= 0 && topRead >= 0 ? Math.min(topRead, topShown) : topRead;
|
|
108
|
+
ordered.forEach((id, index) => {
|
|
109
|
+
if (read.has(id) || unread.has(id)) {
|
|
110
|
+
if (onScreen.has(id) && unread.delete(id))
|
|
111
|
+
remember(read, id);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (limit >= 0 && index < limit && !onScreen.has(id))
|
|
115
|
+
remember(unread, id);
|
|
116
|
+
else
|
|
117
|
+
remember(read, id);
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
seen(id) {
|
|
121
|
+
if (unread.delete(id))
|
|
122
|
+
remember(read, id);
|
|
123
|
+
},
|
|
124
|
+
markRead() {
|
|
125
|
+
for (const id of unread)
|
|
126
|
+
remember(read, id);
|
|
127
|
+
unread.clear();
|
|
128
|
+
},
|
|
129
|
+
count: () => unread.size,
|
|
130
|
+
nextUnread(ordered) {
|
|
131
|
+
for (let i = ordered.length - 1; i >= 0; i--)
|
|
132
|
+
if (unread.has(ordered[i]))
|
|
133
|
+
return ordered[i];
|
|
134
|
+
return null;
|
|
135
|
+
},
|
|
136
|
+
isUnread: id => unread.has(id),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// ---------------------------------------------------------------------------------------------
|
|
140
|
+
// The page module
|
|
141
|
+
const names = (site) => ({
|
|
142
|
+
style: `${site.prefix}-column-css`,
|
|
143
|
+
column: `data-${site.prefix}-column`,
|
|
144
|
+
home: `data-${site.prefix}-column-home`,
|
|
145
|
+
density: `data-${site.prefix}-density`,
|
|
146
|
+
filtered: `data-${site.prefix}-filtered`,
|
|
147
|
+
unread: `data-${site.prefix}-unread`,
|
|
148
|
+
});
|
|
149
|
+
/** Pure: the module's stylesheet. Every rule is scoped to the column attribute on <html>. */
|
|
150
|
+
export function buildColumnCss(site, density) {
|
|
151
|
+
const n = names(site);
|
|
152
|
+
const root = `html[${n.column}]`;
|
|
153
|
+
const rules = [
|
|
154
|
+
site.hide.length ? `${root} :is(${site.hide.join(', ')}) { display: none !important; }` : '',
|
|
155
|
+
site.sourceHide?.length ? `${root}[${n.home}] :is(${site.sourceHide.join(', ')}) { display: none !important; }` : '',
|
|
156
|
+
`${root} ${site.keep} { width: 100% !important; max-width: none !important; min-width: 0 !important; flex: 1 1 auto !important; }`,
|
|
157
|
+
`${root} [${n.filtered}] { display: none !important; }`,
|
|
158
|
+
// Narrow columns scroll without a scrollbar (the deck header shows where you are: unread count).
|
|
159
|
+
`${root} { scrollbar-width: none; }`,
|
|
160
|
+
site.css?.(density) ?? '',
|
|
161
|
+
];
|
|
162
|
+
return rules.filter(Boolean).join('\n');
|
|
163
|
+
}
|
|
164
|
+
export function installColumnMode(win, site, options = {}) {
|
|
165
|
+
const doc = win.document;
|
|
166
|
+
const n = names(site);
|
|
167
|
+
const root = () => doc.documentElement;
|
|
168
|
+
let config = null;
|
|
169
|
+
let matcher = () => false;
|
|
170
|
+
let tracker = createUnreadTracker();
|
|
171
|
+
let watch = null;
|
|
172
|
+
let observer = null;
|
|
173
|
+
const observed = new WeakSet();
|
|
174
|
+
const ids = new WeakMap();
|
|
175
|
+
let prepared = false;
|
|
176
|
+
let lastReported = -1;
|
|
177
|
+
let reportTimer = 0;
|
|
178
|
+
let lastUrl = '';
|
|
179
|
+
let lastSeq = { read: -1, jump: -1 };
|
|
180
|
+
const onSource = () => !!config && isSourcePage(win.location.href, config.url);
|
|
181
|
+
const ensureStyle = () => {
|
|
182
|
+
if (!config)
|
|
183
|
+
return;
|
|
184
|
+
let style = doc.getElementById(n.style);
|
|
185
|
+
if (!style) {
|
|
186
|
+
const parent = doc.head || root();
|
|
187
|
+
if (!parent)
|
|
188
|
+
return;
|
|
189
|
+
style = doc.createElement('style');
|
|
190
|
+
style.id = n.style;
|
|
191
|
+
parent.appendChild(style);
|
|
192
|
+
}
|
|
193
|
+
const css = buildColumnCss(site, config.density);
|
|
194
|
+
if (style.textContent !== css)
|
|
195
|
+
style.textContent = css;
|
|
196
|
+
};
|
|
197
|
+
const kindOf = (item) => site.itemKind?.(item) ?? { reply: false, repost: false, media: false };
|
|
198
|
+
const textOf = (item) => site.itemText?.(item) ?? item.textContent ?? '';
|
|
199
|
+
/** The column is on screen: the page is visible and the webview has a real size (hosts shrink a
|
|
200
|
+
* hidden tab webview to a pixel, and not every engine reports it as hidden). */
|
|
201
|
+
const shown = () => doc.visibilityState !== 'hidden' && win.innerWidth > 40 && win.innerHeight > 40;
|
|
202
|
+
const onScreen = (item) => {
|
|
203
|
+
if (!shown())
|
|
204
|
+
return false;
|
|
205
|
+
const box = item.getBoundingClientRect();
|
|
206
|
+
const height = win.innerHeight || doc.documentElement.clientHeight;
|
|
207
|
+
// Mostly in view: its top is on screen and at least 40 px (or all of it) is visible.
|
|
208
|
+
return box.bottom > 0 && box.top < height && Math.min(box.bottom, height) - Math.max(box.top, 0) >= Math.min(40, box.height);
|
|
209
|
+
};
|
|
210
|
+
const pending = () => {
|
|
211
|
+
try {
|
|
212
|
+
return Math.max(0, Math.floor(site.pendingCount?.(doc) ?? 0));
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const report = () => {
|
|
219
|
+
if (!options.onUnread)
|
|
220
|
+
return;
|
|
221
|
+
const count = config?.unread ? Math.min(999, tracker.count() + pending()) : 0;
|
|
222
|
+
if (count === lastReported)
|
|
223
|
+
return;
|
|
224
|
+
if (reportTimer)
|
|
225
|
+
return;
|
|
226
|
+
reportTimer = win.setTimeout(() => {
|
|
227
|
+
reportTimer = 0;
|
|
228
|
+
const now = config?.unread ? Math.min(999, tracker.count() + pending()) : 0;
|
|
229
|
+
if (now === lastReported)
|
|
230
|
+
return;
|
|
231
|
+
lastReported = now;
|
|
232
|
+
try {
|
|
233
|
+
options.onUnread?.(now);
|
|
234
|
+
}
|
|
235
|
+
catch { /* reporting is best effort */ }
|
|
236
|
+
}, 250);
|
|
237
|
+
};
|
|
238
|
+
const ensureObserver = () => {
|
|
239
|
+
if (observer || typeof win.IntersectionObserver !== 'function')
|
|
240
|
+
return;
|
|
241
|
+
observer = new win.IntersectionObserver(entries => {
|
|
242
|
+
if (!shown())
|
|
243
|
+
return;
|
|
244
|
+
let changed = false;
|
|
245
|
+
for (const entry of entries) {
|
|
246
|
+
if (!entry.isIntersecting)
|
|
247
|
+
continue;
|
|
248
|
+
const id = ids.get(entry.target);
|
|
249
|
+
if (id && tracker.isUnread(id)) {
|
|
250
|
+
tracker.seen(id);
|
|
251
|
+
changed = true;
|
|
252
|
+
}
|
|
253
|
+
if (id)
|
|
254
|
+
entry.target.removeAttribute(n.unread);
|
|
255
|
+
}
|
|
256
|
+
if (changed)
|
|
257
|
+
report();
|
|
258
|
+
}, { threshold: [0, 0.5, 1] });
|
|
259
|
+
};
|
|
260
|
+
const items = () => Array.from(doc.querySelectorAll(site.itemSelector));
|
|
261
|
+
const scan = () => {
|
|
262
|
+
if (!config)
|
|
263
|
+
return;
|
|
264
|
+
const html = root();
|
|
265
|
+
if (!html)
|
|
266
|
+
return;
|
|
267
|
+
// A config delivered at document start arrives before the parser has created <html>.
|
|
268
|
+
if (!html.hasAttribute(n.column))
|
|
269
|
+
html.setAttribute(n.column, '');
|
|
270
|
+
if (html.getAttribute(n.density) !== config.density)
|
|
271
|
+
html.setAttribute(n.density, config.density);
|
|
272
|
+
ensureStyle();
|
|
273
|
+
const source = onSource();
|
|
274
|
+
if (source)
|
|
275
|
+
html.setAttribute(n.home, '');
|
|
276
|
+
else
|
|
277
|
+
html.removeAttribute(n.home);
|
|
278
|
+
if (win.location.href !== lastUrl) {
|
|
279
|
+
lastUrl = win.location.href;
|
|
280
|
+
prepared = false;
|
|
281
|
+
}
|
|
282
|
+
if (source && !prepared && site.prepare) {
|
|
283
|
+
try {
|
|
284
|
+
prepared = site.prepare(doc, config);
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
prepared = true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const list = items();
|
|
291
|
+
const ordered = [];
|
|
292
|
+
const visible = new Set();
|
|
293
|
+
for (const item of list) {
|
|
294
|
+
const container = site.container?.(item) ?? item;
|
|
295
|
+
let hidden = false;
|
|
296
|
+
if (source) {
|
|
297
|
+
try {
|
|
298
|
+
hidden = matcher({ text: textOf(item), ...kindOf(item) });
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
hidden = false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (hidden)
|
|
305
|
+
container.setAttribute(n.filtered, '');
|
|
306
|
+
else if (container.hasAttribute(n.filtered))
|
|
307
|
+
container.removeAttribute(n.filtered);
|
|
308
|
+
if (!source || !config.unread || hidden)
|
|
309
|
+
continue;
|
|
310
|
+
let id = null;
|
|
311
|
+
try {
|
|
312
|
+
id = site.itemId(item);
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
id = null;
|
|
316
|
+
}
|
|
317
|
+
if (!id || ordered.includes(id))
|
|
318
|
+
continue;
|
|
319
|
+
ids.set(item, id);
|
|
320
|
+
ordered.push(id);
|
|
321
|
+
if (onScreen(item))
|
|
322
|
+
visible.add(id);
|
|
323
|
+
ensureObserver();
|
|
324
|
+
if (observer && !observed.has(item)) {
|
|
325
|
+
observed.add(item);
|
|
326
|
+
observer.observe(item);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (source && config.unread) {
|
|
330
|
+
tracker.observe(ordered, visible);
|
|
331
|
+
for (const item of list) {
|
|
332
|
+
const id = ids.get(item);
|
|
333
|
+
if (!id)
|
|
334
|
+
continue;
|
|
335
|
+
if (tracker.isUnread(id))
|
|
336
|
+
item.setAttribute(n.unread, '');
|
|
337
|
+
else if (item.hasAttribute(n.unread))
|
|
338
|
+
item.removeAttribute(n.unread);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
report();
|
|
342
|
+
};
|
|
343
|
+
const onKey = (event) => {
|
|
344
|
+
if (!config || !event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
|
|
345
|
+
return;
|
|
346
|
+
const key = event.key.toLowerCase();
|
|
347
|
+
if (key !== 'r' && key !== 'u')
|
|
348
|
+
return;
|
|
349
|
+
event.preventDefault();
|
|
350
|
+
event.stopImmediatePropagation();
|
|
351
|
+
if (key === 'r')
|
|
352
|
+
handle.markRead();
|
|
353
|
+
else
|
|
354
|
+
handle.jumpToUnread();
|
|
355
|
+
};
|
|
356
|
+
const onVisibility = () => { if (shown())
|
|
357
|
+
watch?.schedule(); };
|
|
358
|
+
const start = () => {
|
|
359
|
+
if (watch)
|
|
360
|
+
return;
|
|
361
|
+
watch = watchDom(win, scan, { phase: 'write' });
|
|
362
|
+
win.addEventListener('keydown', onKey, true);
|
|
363
|
+
doc.addEventListener('visibilitychange', onVisibility);
|
|
364
|
+
win.addEventListener('resize', onVisibility);
|
|
365
|
+
win.addEventListener('scroll', onScroll, { passive: true });
|
|
366
|
+
};
|
|
367
|
+
let scrollFrame = 0;
|
|
368
|
+
const onScroll = () => {
|
|
369
|
+
if (scrollFrame)
|
|
370
|
+
return;
|
|
371
|
+
scrollFrame = win.requestAnimationFrame(() => { scrollFrame = 0; report(); });
|
|
372
|
+
};
|
|
373
|
+
const stop = () => {
|
|
374
|
+
watch?.dispose();
|
|
375
|
+
watch = null;
|
|
376
|
+
observer?.disconnect();
|
|
377
|
+
observer = null;
|
|
378
|
+
win.removeEventListener('keydown', onKey, true);
|
|
379
|
+
doc.removeEventListener('visibilitychange', onVisibility);
|
|
380
|
+
win.removeEventListener('resize', onVisibility);
|
|
381
|
+
win.removeEventListener('scroll', onScroll);
|
|
382
|
+
if (reportTimer) {
|
|
383
|
+
win.clearTimeout(reportTimer);
|
|
384
|
+
reportTimer = 0;
|
|
385
|
+
}
|
|
386
|
+
const html = root();
|
|
387
|
+
html?.removeAttribute(n.column);
|
|
388
|
+
html?.removeAttribute(n.home);
|
|
389
|
+
html?.removeAttribute(n.density);
|
|
390
|
+
doc.getElementById(n.style)?.remove();
|
|
391
|
+
for (const el of Array.from(doc.querySelectorAll(`[${n.filtered}], [${n.unread}]`))) {
|
|
392
|
+
el.removeAttribute(n.filtered);
|
|
393
|
+
el.removeAttribute(n.unread);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
const handle = {
|
|
397
|
+
set(value) {
|
|
398
|
+
const next = normalizeColumnConfig(value);
|
|
399
|
+
if (!next) {
|
|
400
|
+
if (config) {
|
|
401
|
+
config = null;
|
|
402
|
+
stop();
|
|
403
|
+
lastReported = -1;
|
|
404
|
+
options.onUnread?.(0);
|
|
405
|
+
}
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const first = !config;
|
|
409
|
+
const sourceChanged = !!config && config.url !== next.url;
|
|
410
|
+
config = next;
|
|
411
|
+
matcher = compileFilters(next.filters);
|
|
412
|
+
if (first || sourceChanged) {
|
|
413
|
+
tracker = createUnreadTracker();
|
|
414
|
+
prepared = false;
|
|
415
|
+
}
|
|
416
|
+
const html = root();
|
|
417
|
+
html?.setAttribute(n.column, '');
|
|
418
|
+
html?.setAttribute(n.density, next.density);
|
|
419
|
+
if (!first && lastSeq.read >= 0 && next.readSeq !== lastSeq.read)
|
|
420
|
+
handle.markRead();
|
|
421
|
+
if (!first && lastSeq.jump >= 0 && next.jumpSeq !== lastSeq.jump)
|
|
422
|
+
handle.jumpToUnread();
|
|
423
|
+
lastSeq = { read: next.readSeq, jump: next.jumpSeq };
|
|
424
|
+
ensureStyle();
|
|
425
|
+
start();
|
|
426
|
+
watch?.schedule();
|
|
427
|
+
if (!next.unread)
|
|
428
|
+
report();
|
|
429
|
+
},
|
|
430
|
+
markRead() {
|
|
431
|
+
tracker.markRead();
|
|
432
|
+
for (const el of Array.from(doc.querySelectorAll(`[${n.unread}]`)))
|
|
433
|
+
el.removeAttribute(n.unread);
|
|
434
|
+
report();
|
|
435
|
+
},
|
|
436
|
+
jumpToUnread() {
|
|
437
|
+
const list = items();
|
|
438
|
+
const ordered = list.map(item => ids.get(item)).filter((id) => !!id);
|
|
439
|
+
const target = tracker.nextUnread(ordered);
|
|
440
|
+
const element = target ? list.find(item => ids.get(item) === target) : null;
|
|
441
|
+
if (element)
|
|
442
|
+
(site.container?.(element) ?? element).scrollIntoView({ block: 'start' });
|
|
443
|
+
else if (pending() > 0)
|
|
444
|
+
win.scrollTo({ top: 0 });
|
|
445
|
+
},
|
|
446
|
+
unread: () => (config?.unread ? Math.min(999, tracker.count() + pending()) : 0),
|
|
447
|
+
dispose() { config = null; stop(); },
|
|
448
|
+
};
|
|
449
|
+
return handle;
|
|
450
|
+
}
|
|
451
|
+
//# sourceMappingURL=column.js.map
|