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/dist/shell/paneModel.js
CHANGED
|
@@ -26,7 +26,7 @@ export function redundantNavPanes(panes, isSiteUrl) {
|
|
|
26
26
|
const lead = new Map();
|
|
27
27
|
const redundant = new Set();
|
|
28
28
|
const ordered = panes
|
|
29
|
-
.filter(pane => pane.visible && isSiteUrl(pane.url))
|
|
29
|
+
.filter(pane => pane.visible && pane.role !== 'column' && isSiteUrl(pane.url))
|
|
30
30
|
.sort((a, b) => a.x - b.x || a.y - b.y || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
31
31
|
for (const pane of ordered) {
|
|
32
32
|
if (lead.has(pane.profile))
|
|
@@ -53,4 +53,27 @@ export function withNavRedundant(boxes, isSiteUrl, memory) {
|
|
|
53
53
|
memory.delete(id);
|
|
54
54
|
return items;
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* A tab webview's `visible`/`parked` for `tabs_sync`. `shown`: its pane is on screen in the shell;
|
|
58
|
+
* `overlay`: shell overlays open (menus, dialogs, palette, drags); `raiseSupported`: the shell can
|
|
59
|
+
* be raised above the tab webviews for them (`shell_raise`), so panes stay visible under
|
|
60
|
+
* the overlay. Where it cannot, an overlay hides every tab (the shell would draw under them). An
|
|
61
|
+
* overlay never parks (drops to low memory) a tab: only a pane that is not shown is parked.
|
|
62
|
+
*/
|
|
63
|
+
export function paneVisibility(pane) {
|
|
64
|
+
return { visible: pane.shown && (pane.raiseSupported || pane.overlay === 0), parked: !pane.shown };
|
|
65
|
+
}
|
|
66
|
+
/** `shell_raise`'s startup probe (`probe`: its answer) unless the developer switch turned raising off. */
|
|
67
|
+
export function raiseSupported(probe, devOff) {
|
|
68
|
+
return probe === true && !devOff;
|
|
69
|
+
}
|
|
70
|
+
/** `[r, g, b]` of a computed CSS color (`rgb(...)`/`rgba(...)`), or null (unparsable or fully transparent). */
|
|
71
|
+
export function cssRgb(color) {
|
|
72
|
+
const parts = /^rgba?\(([^)]+)\)$/.exec(color.trim())?.[1]?.split(/[\s,/]+/).filter(Boolean).map(Number);
|
|
73
|
+
if (!parts || parts.length < 3 || parts.slice(0, 3).some(n => !Number.isFinite(n)))
|
|
74
|
+
return null;
|
|
75
|
+
if (parts.length > 3 && parts[3] === 0)
|
|
76
|
+
return null;
|
|
77
|
+
return [0, 1, 2].map(i => Math.max(0, Math.min(255, Math.round(parts[i]))));
|
|
78
|
+
}
|
|
56
79
|
//# sourceMappingURL=paneModel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paneModel.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"paneModel.js","sourceRoot":"","sources":["../../../../../shell/src/paneModel.ts"],"names":[],"mappings":"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","sourcesContent":["// Pane geometry rules for the dock: where a link opened \"beside\" a pane goes, and which site panes\n// repeat a navigation rail already on screen. Two site panes of the same account side by side (or\n// stacked) both draw the site's rail; only the leftmost (then topmost) one needs it. Panes of\n// different accounts keep theirs: the rail's account button is the only in-page sign of which\n// account a pane is.\n\n/** `role`: 'column' boxes are deck columns (Power User Mode); they hide the site's chrome themselves\n * and never take part in the rail rules. Missing = an ordinary pane. */\nexport type PaneBox = { id: string; url: string; profile: string; x: number; y: number; visible: boolean; role?: 'pane' | 'column' };\n\n/** `besideOf`: the source group ids whose \"beside\" links this group's tabs were opened for. */\nexport type GroupBox = { id: string; left: number; top: number; right: number; bottom: number; besideOf?: readonly string[] };\n\n/**\n * Where a link opened \"beside\" a pane goes: the side pane this source opened before (so repeated\n * links reuse one), when it is still to its right and shares some of its height; else null to split\n * a new one. A group the user opened themselves (another feed, another account) is never taken over.\n */\nexport function besideGroup(source: GroupBox, groups: readonly GroupBox[]): string | null {\n let best: GroupBox | null = null;\n for (const group of groups) {\n if (group.id === source.id || !group.besideOf?.includes(source.id)) continue;\n const overlap = Math.min(group.bottom, source.bottom) - Math.max(group.top, source.top);\n if (group.left < source.right - 4 || overlap <= 0) continue;\n if (!best || group.left < best.left || (group.left === best.left && group.top < best.top)) best = group;\n }\n return best?.id ?? null;\n}\n\n/** Ids of visible site panes whose navigation duplicates the leftmost site pane of the same account. */\nexport function redundantNavPanes(panes: readonly PaneBox[], isSiteUrl: (url: string) => boolean): Set<string> {\n const lead = new Map<string, PaneBox>();\n const redundant = new Set<string>();\n const ordered = panes\n .filter(pane => pane.visible && pane.role !== 'column' && isSiteUrl(pane.url))\n .sort((a, b) => a.x - b.x || a.y - b.y || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));\n for (const pane of ordered) {\n if (lead.has(pane.profile)) redundant.add(pane.id);\n else lead.set(pane.profile, pane);\n }\n return redundant;\n}\n\n/**\n * The `navRedundant` flag per tab for `tabs_sync`. Only visible panes are judged (a shell overlay\n * hides them all and so changes nothing); a hidden tab keeps its last value (`memory`) so it shows\n * up again without a flicker. Tabs that are gone are forgotten.\n */\nexport function withNavRedundant<T extends PaneBox>(boxes: readonly T[], isSiteUrl: (url: string) => boolean, memory: Map<string, boolean>): Array<T & { navRedundant: boolean }> {\n const redundant = redundantNavPanes(boxes, isSiteUrl);\n const items = boxes.map(box => {\n if (box.visible) memory.set(box.id, redundant.has(box.id));\n return { ...box, navRedundant: memory.get(box.id) ?? false };\n });\n for (const id of memory.keys()) if (!boxes.some(box => box.id === id)) memory.delete(id);\n return items;\n}\n\n/**\n * A tab webview's `visible`/`parked` for `tabs_sync`. `shown`: its pane is on screen in the shell;\n * `overlay`: shell overlays open (menus, dialogs, palette, drags); `raiseSupported`: the shell can\n * be raised above the tab webviews for them (`shell_raise`), so panes stay visible under\n * the overlay. Where it cannot, an overlay hides every tab (the shell would draw under them). An\n * overlay never parks (drops to low memory) a tab: only a pane that is not shown is parked.\n */\nexport function paneVisibility(pane: { shown: boolean; overlay: number; raiseSupported: boolean }): { visible: boolean; parked: boolean } {\n return { visible: pane.shown && (pane.raiseSupported || pane.overlay === 0), parked: !pane.shown };\n}\n\n/** `shell_raise`'s startup probe (`probe`: its answer) unless the developer switch turned raising off. */\nexport function raiseSupported(probe: unknown, devOff: boolean): boolean {\n return probe === true && !devOff;\n}\n\n/** `[r, g, b]` of a computed CSS color (`rgb(...)`/`rgba(...)`), or null (unparsable or fully transparent). */\nexport function cssRgb(color: string): [number, number, number] | null {\n const parts = /^rgba?\\(([^)]+)\\)$/.exec(color.trim())?.[1]?.split(/[\\s,/]+/).filter(Boolean).map(Number);\n if (!parts || parts.length < 3 || parts.slice(0, 3).some(n => !Number.isFinite(n))) return null;\n if (parts.length > 3 && parts[3] === 0) return null;\n return [0, 1, 2].map(i => Math.max(0, Math.min(255, Math.round(parts[i]!)))) as [number, number, number];\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ThemeSpec } from '../../runtime/themeSpec.ts';
|
|
2
|
+
import { type Notify } from './site.ts';
|
|
3
|
+
import './builder.css';
|
|
4
|
+
/** Built-in themes have translated descriptions (`theme.<id>.description` in the app's catalog); imported ones keep their own. */
|
|
5
|
+
export declare const themeDescription: (theme: ThemeSpec) => string;
|
|
6
|
+
export declare function Appearance({ notify }: {
|
|
7
|
+
notify: Notify;
|
|
8
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// Appearance: the theme gallery (live previews rendered from each theme document), per-group
|
|
3
|
+
// customization on top of the selected theme (fonts per role with the Google Fonts browser),
|
|
4
|
+
// account and pane themes, downloaded fonts, import/export of theme JSON and Custom CSS. The theme
|
|
5
|
+
// documents, the store and the miniature are the app's (`PanelSite.themes`).
|
|
6
|
+
import { useEffect, useRef, useState } from 'react';
|
|
7
|
+
import { THEME_SCHEMA_URL } from "../../runtime/themeApi.js";
|
|
8
|
+
import { FONT_CHOICES, MAX_IMAGE_CHARS, fontChoiceOf, googleFontsUsed, parseThemeJson, slug, } from "../../runtime/themeSpec.js";
|
|
9
|
+
import { AccountAvatar, accountName, useProfiles } from "../frame/AccountSwitcher.js";
|
|
10
|
+
import { useT } from "../frame/hooks.js";
|
|
11
|
+
import { formatDate, t, tx } from "../frame/i18n.js";
|
|
12
|
+
import { ThemeDots } from "../frame/PaneTheme.js";
|
|
13
|
+
import { shell } from "../frame/state.js";
|
|
14
|
+
import { assign } from "../frame/themeScopes.js";
|
|
15
|
+
import { tabProfile } from "../profileModel.js";
|
|
16
|
+
import { Badge, Button, ColorField, Row, Section, Segmented, Select, Slider, Toggle, useSettingsQuery } from "./controls.js";
|
|
17
|
+
import { IconPackImport, IconPackReview } from "./IconPackInstall.js";
|
|
18
|
+
import { themeDoctor } from "../../runtime/themeDoctor.js";
|
|
19
|
+
import { bytesLabel, defaultWeights, loadCatalog, weightsLabel } from "./fonts/catalog.js";
|
|
20
|
+
import { FontRoles } from "./fonts/FontRoles.js";
|
|
21
|
+
import { CustomCssEditor } from "./Plugins.js";
|
|
22
|
+
import { panelSite, panelThemes } from "./site.js";
|
|
23
|
+
import { useThemeState } from "./themes.js";
|
|
24
|
+
import './builder.css';
|
|
25
|
+
const getError = (error) => error instanceof Error ? error.message : String(error);
|
|
26
|
+
const CORNERS = [
|
|
27
|
+
{ value: 'square', label: 'wb.appearance.corners.square', radius: 0, button: 0 },
|
|
28
|
+
{ value: 'crisp', label: 'wb.appearance.corners.crisp', radius: 5, button: 5 },
|
|
29
|
+
{ value: 'soft', label: 'wb.appearance.corners.soft', radius: 12, button: 10 },
|
|
30
|
+
{ value: 'round', label: 'wb.appearance.corners.round', radius: 16, button: 9999 },
|
|
31
|
+
];
|
|
32
|
+
const backgrounds = () => [
|
|
33
|
+
{ value: 'none', label: t('wb.appearance.bg.none') }, { value: 'glow', label: t('wb.appearance.bg.glow') }, { value: 'dots', label: t('wb.appearance.bg.dots') }, { value: 'grid', label: t('wb.appearance.bg.grid') },
|
|
34
|
+
{ value: 'diagonal', label: t('wb.appearance.bg.diagonal') }, { value: 'scanlines', label: t('wb.appearance.bg.scanlines') }, { value: 'paper', label: t('wb.appearance.bg.paper') },
|
|
35
|
+
{ value: 'clouds', label: t('wb.appearance.bg.clouds') }, { value: 'image', label: t('wb.appearance.bg.image'), hint: t('wb.appearance.bg.imageHint') },
|
|
36
|
+
];
|
|
37
|
+
const modeLabel = (theme) => theme.mode === 'auto' ? t('wb.appearance.mode.auto') : theme.mode === 'light' ? t('wb.appearance.mode.light') : t('wb.appearance.mode.dark');
|
|
38
|
+
const fontLabel = (theme) => {
|
|
39
|
+
const family = theme.font.family;
|
|
40
|
+
const choices = panelThemes().fontChoices ?? FONT_CHOICES;
|
|
41
|
+
const choice = choices.find(item => item.id === fontChoiceOf(family, choices));
|
|
42
|
+
return (choice?.key ? tx(choice.key, undefined, choice.label) : choice?.label) ?? family[0] ?? panelThemes().siteFont;
|
|
43
|
+
};
|
|
44
|
+
/** Built-in themes have translated descriptions (`theme.<id>.description` in the app's catalog); imported ones keep their own. */
|
|
45
|
+
export const themeDescription = (theme) => tx(`theme.${theme.id}.description`, undefined, theme.description);
|
|
46
|
+
const formatPercent = (value) => t('wb.appearance.percent', { value: value / 100 });
|
|
47
|
+
const hasOverrides = (choice) => !!choice.accent || Object.keys(choice.overrides).length > 0;
|
|
48
|
+
function download(name, text) {
|
|
49
|
+
const url = URL.createObjectURL(new Blob([text], { type: 'application/json' }));
|
|
50
|
+
const anchor = document.createElement('a');
|
|
51
|
+
anchor.href = url;
|
|
52
|
+
anchor.download = name;
|
|
53
|
+
anchor.click();
|
|
54
|
+
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
|
55
|
+
}
|
|
56
|
+
function backgroundFor(kind, theme, image) {
|
|
57
|
+
const base = panelThemes().draftColors;
|
|
58
|
+
const text = theme.colors?.text ?? '#8b98a5';
|
|
59
|
+
const light = theme.mode === 'light';
|
|
60
|
+
switch (kind) {
|
|
61
|
+
case 'none': return { kind: 'none' };
|
|
62
|
+
case 'glow': return { kind: 'gradient', from: theme.colors?.page ?? theme.colors?.bg ?? base.bg, to: theme.colors?.page ?? theme.colors?.bg ?? base.bg, angle: 180, glow: theme.colors?.accent ?? base.accent };
|
|
63
|
+
case 'image': return { kind: 'image', url: image ?? '', fit: 'cover', dim: light ? 0.55 : 0.6 };
|
|
64
|
+
case 'clouds': return { kind: 'pattern', pattern: 'clouds', ink: light ? '#ffffff' : text, opacity: light ? 0.55 : 0.07, size: 220 };
|
|
65
|
+
case 'dots': return { kind: 'pattern', pattern: 'dots', ink: text, opacity: 0.16, size: 18 };
|
|
66
|
+
case 'grid': return { kind: 'pattern', pattern: 'grid', ink: text, opacity: 0.06, size: 28 };
|
|
67
|
+
case 'diagonal': return { kind: 'pattern', pattern: 'diagonal', ink: text, opacity: 0.06, size: 10 };
|
|
68
|
+
case 'scanlines': return { kind: 'pattern', pattern: 'scanlines', ink: theme.colors?.accent ?? text, opacity: 0.05, size: 4 };
|
|
69
|
+
case 'paper': return { kind: 'pattern', pattern: 'paper', ink: light ? '#7a6a50' : text, opacity: 0.1, size: 180 };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const backgroundChoice = (background) => background.kind === 'none' ? 'none' : background.kind === 'gradient' ? 'glow' : background.kind === 'image' ? 'image' : background.pattern;
|
|
73
|
+
/** Asks the panel to show another section (the Theme Builder). */
|
|
74
|
+
const openSection = (section) => window.dispatchEvent(new CustomEvent('bt-panel-section', { detail: section }));
|
|
75
|
+
export function Appearance({ notify }) {
|
|
76
|
+
const t = useT();
|
|
77
|
+
const themes = panelThemes();
|
|
78
|
+
const { allThemes, installFont, missingFonts, setChoice, setScopes } = themes.store;
|
|
79
|
+
const ThemePreview = themes.Preview;
|
|
80
|
+
const { ready, choice, scopes } = useThemeState();
|
|
81
|
+
const [importing, setImporting] = useState(false);
|
|
82
|
+
const [asking, setAsking] = useState(null);
|
|
83
|
+
const [packReview, setPackReview] = useState(null);
|
|
84
|
+
const query = useSettingsQuery();
|
|
85
|
+
if (!ready)
|
|
86
|
+
return null;
|
|
87
|
+
const effective = themes.catalog.resolve(choice);
|
|
88
|
+
const base = themes.catalog.base(choice);
|
|
89
|
+
const all = allThemes(choice);
|
|
90
|
+
const siteTheme = themes.catalog.defaultChoice.preset;
|
|
91
|
+
const suffix = themes.fileSuffix ?? '.theme.json';
|
|
92
|
+
const update = (next, commit = true) => setChoice(next, commit).catch(error => notify(getError(error), true));
|
|
93
|
+
const override = (patch, commit = true) => {
|
|
94
|
+
const overrides = { ...choice.overrides };
|
|
95
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
96
|
+
overrides[key] = key === 'background' ? value : { ...choice.overrides[key], ...value };
|
|
97
|
+
}
|
|
98
|
+
return update({ ...choice, overrides }, commit);
|
|
99
|
+
};
|
|
100
|
+
const setRole = (role, next, commit = true) => override({ font: { roles: { ...(choice.overrides.font?.roles ?? {}), [role]: next } } }, commit);
|
|
101
|
+
function select(id) {
|
|
102
|
+
if (id === choice.preset)
|
|
103
|
+
return;
|
|
104
|
+
// Customizations belong to the theme they were made on; switching starts clean.
|
|
105
|
+
void update({ ...choice, preset: id, overrides: {}, accent: null });
|
|
106
|
+
}
|
|
107
|
+
function remove(theme) {
|
|
108
|
+
const themes = choice.themes.filter(item => item.id !== theme.id);
|
|
109
|
+
void update({ ...choice, themes, ...(choice.preset === theme.id ? { preset: siteTheme, overrides: {}, accent: null } : {}) }).then(() => notify(t('wb.appearance.removedTheme', { name: theme.name })));
|
|
110
|
+
}
|
|
111
|
+
function add(theme, message) {
|
|
112
|
+
let id = theme.id;
|
|
113
|
+
for (let n = 2; all.some(item => item.id === id); n++)
|
|
114
|
+
id = `${theme.id.slice(0, 36)}-${n}`;
|
|
115
|
+
void update({ ...choice, themes: [...choice.themes, { ...theme, id }], preset: id, overrides: {}, accent: null }).then(() => notify(message));
|
|
116
|
+
}
|
|
117
|
+
function exportTheme() {
|
|
118
|
+
const custom = hasOverrides(choice);
|
|
119
|
+
const doc = { ...effective, ...(custom ? { id: slug(`${effective.name} custom`), name: t('wb.appearance.customName', { name: effective.name }) } : {}) };
|
|
120
|
+
// `$schema` lets editors validate and complete the file; imports ignore it.
|
|
121
|
+
download(`${doc.id}${suffix}`, JSON.stringify({ $schema: THEME_SCHEMA_URL, ...doc }, null, 2));
|
|
122
|
+
}
|
|
123
|
+
function saveAsNew() {
|
|
124
|
+
const name = t('wb.appearance.savedName', { name: base.name });
|
|
125
|
+
add({ ...effective, id: slug(`${base.name} custom`), name, author: t('wb.appearance.you'), description: t('wb.appearance.basedOn', { name: base.name }) }, t('wb.appearance.saved', { name }));
|
|
126
|
+
}
|
|
127
|
+
/** An imported theme that names Google fonts asks before anything is downloaded. */
|
|
128
|
+
function imported(theme, warnings) {
|
|
129
|
+
setImporting(false);
|
|
130
|
+
add(theme, `${t('wb.appearance.imported', { name: theme.name })}${warnings.length ? ` ${warnings.join(' ')}` : ''}`);
|
|
131
|
+
const families = missingFonts(theme);
|
|
132
|
+
if (families.length)
|
|
133
|
+
setAsking({ theme, families });
|
|
134
|
+
}
|
|
135
|
+
async function downloadFonts(families) {
|
|
136
|
+
setAsking(null);
|
|
137
|
+
const catalog = await loadCatalog();
|
|
138
|
+
for (const family of families) {
|
|
139
|
+
const font = catalog.find(item => item.family === family);
|
|
140
|
+
try {
|
|
141
|
+
await installFont(family, font ? defaultWeights(font) : { kind: 'list', values: [400, 700] });
|
|
142
|
+
notify(t('wb.appearance.downloadedFont', { family }));
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
notify(`${family}: ${getError(error)}`, true);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const cornerValue = CORNERS.find(corner => corner.radius === effective.shape.radius && corner.button === effective.shape.button)?.value ?? null;
|
|
150
|
+
const timeline = effective.layout.cards ? 'cards' : effective.layout.frame ? 'framed' : 'flat';
|
|
151
|
+
async function pickImage(file) {
|
|
152
|
+
if (!file)
|
|
153
|
+
return;
|
|
154
|
+
if (!/^image\/(png|jpeg|webp|gif|avif)$/.test(file.type)) {
|
|
155
|
+
notify(t('wb.appearance.imageType'), true);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const url = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(String(reader.result)); reader.onerror = () => reject(reader.error); reader.readAsDataURL(file); });
|
|
159
|
+
if (url.length > MAX_IMAGE_CHARS) {
|
|
160
|
+
notify(t('wb.appearance.imageTooLarge'), true);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
void override({ background: backgroundFor('image', effective, url) });
|
|
164
|
+
}
|
|
165
|
+
const searching = !!query;
|
|
166
|
+
return _jsxs(_Fragment, { children: [!searching && _jsxs(Section, { title: t('wb.appearance.theme'), id: "themes", hint: t('wb.appearance.themeHint'), action: _jsxs("div", { className: "bt-inline", children: [_jsx(Button, { size: "sm", tone: "ghost", onClick: () => setImporting(!importing), icon: _jsx(Glyph, { d: "M8 2v8m0 0L5 7m3 3 3-3M3 13h10" }), children: t('wb.common.import') }), _jsx(Button, { size: "sm", tone: "ghost", onClick: exportTheme, icon: _jsx(Glyph, { d: "M8 11V3m0 0L5 6m3-3 3 3M3 13h10" }), children: t('wb.common.export') }), _jsx(Button, { size: "sm", tone: "primary", onClick: () => openSection('builder'), icon: _jsx(Glyph, { d: "M3 13l.6-2.6L10.5 3.5l2 2-6.9 6.9zM9 5l2 2" }), children: t('wb.panel.section.builder') })] }), children: [importing && _jsx(ImportPanel, { onCancel: () => setImporting(false), onImport: imported }), asking && _jsx("div", { className: "bt-import wb-ask", role: "alertdialog", "aria-label": t('wb.appearance.askFonts'), children: _jsxs("div", { className: "bt-import-drop", children: [_jsx("strong", { children: t('wb.appearance.askFontsTitle', { name: asking.theme.name, fonts: asking.families.join(', ') }) }), _jsx("p", { children: t('wb.appearance.askFontsText', { count: asking.families.length }) }), _jsxs("div", { className: "bt-inline", children: [_jsx(Button, { size: "sm", tone: "primary", onClick: () => void downloadFonts(asking.families), children: t('wb.panel.updates.download') }), _jsx(Button, { size: "sm", tone: "ghost", onClick: () => setAsking(null), children: t('wb.common.notNow') })] })] }) }), _jsx("div", { className: "bt-gallery", role: "radiogroup", "aria-label": t('wb.appearance.theme'), children: all.map(theme => {
|
|
167
|
+
const on = theme.id === choice.preset;
|
|
168
|
+
const isImported = choice.themes.some(item => item.id === theme.id);
|
|
169
|
+
return _jsxs("div", { className: `bt-theme ${on ? 'is-on' : ''}`, children: [_jsxs("button", { type: "button", role: "radio", "aria-checked": on, className: "bt-theme-hit", onClick: () => select(theme.id), "aria-label": `${theme.name}. ${themeDescription(theme)}`, children: [_jsx(ThemePreview, { theme: on ? effective : theme }), _jsxs("span", { className: "bt-theme-info", children: [_jsxs("span", { className: "bt-theme-title", children: [_jsx("strong", { children: theme.name }), on && _jsx("span", { className: "bt-theme-check", "aria-hidden": "true", children: _jsx(Glyph, { d: "m4 8.5 2.5 2.5L12 5.5" }) })] }), _jsx("small", { children: themeDescription(theme) }), _jsxs("span", { className: "bt-theme-tags", children: [_jsx("em", { children: modeLabel(theme) }), _jsx("em", { children: fontLabel(theme) }), theme.layout.cards && _jsx("em", { children: t('wb.appearance.timeline.cards') }), googleFontsUsed(theme).length > 0 && _jsx("em", { children: "Google Fonts" }), isImported && _jsx("em", { className: "is-accent", children: t('wb.appearance.yours') }), theme.css && _jsx("em", { children: "CSS" })] })] })] }), isImported && _jsx("button", { type: "button", className: "bt-theme-remove", "aria-label": t('wb.appearance.removeNamed', { name: theme.name }), title: t('wb.appearance.removeTheme'), onClick: () => remove(theme), children: _jsx(Glyph, { d: "m4.5 4.5 7 7m0-7-7 7" }) })] }, theme.id);
|
|
170
|
+
}) })] }), _jsxs(Section, { title: searching ? t('wb.appearance.theme') : t('wb.appearance.customize', { name: base.name }), id: "customize", hint: searching ? undefined : t('wb.appearance.customizeHint'), action: !searching && hasOverrides(choice) ? _jsxs("div", { className: "bt-inline", children: [_jsx(Button, { size: "sm", tone: "ghost", onClick: () => void update({ ...choice, overrides: {}, accent: null }), children: t('wb.common.reset') }), _jsx(Button, { size: "sm", onClick: saveAsNew, children: t('wb.appearance.saveAsTheme') })] }) : undefined, children: [_jsx(Row, { label: t('wb.appearance.accent'), hint: t('wb.appearance.accentHint'), keywords: "color colour highlight link", wide: true, children: _jsx(ColorField, { label: t('wb.appearance.accentColor'), value: choice.accent, swatches: [...themes.accents], autoLabel: t('wb.appearance.theme'), onChange: accent => void update({ ...choice, accent }) }) }), themes.iconPacks?.length ? _jsx(Row, { label: t('wb.appearance.icons'), hint: t('wb.appearance.iconsHint'), keywords: "icon pack glyphs symbols pixel import", wide: true, children: _jsxs("div", { className: "wb-pack-row", children: [_jsxs("div", { className: "bt-inline", children: [_jsx(Select, { label: t('wb.appearance.icons'), value: choice.icons ?? 'theme', width: 220, onChange: icons => void update({ ...choice, icons: icons === 'theme' ? undefined : icons }), options: [{ value: 'theme', label: t('wb.appearance.icons.theme') }, { value: 'site', label: t('wb.appearance.icons.site') }, ...themes.iconPacks.filter(pack => !choice.packs?.some(item => item.id === pack.id)).map(pack => ({ value: pack.id, label: pack.name })), ...(choice.packs ?? []).map(pack => ({ value: pack.id, label: pack.name }))] }), _jsx(IconPackImport, { onError: message => notify(message, true), onParsed: (pack, warnings, bytes) => setPackReview({ pack, warnings, bytes }) })] }), choice.packs?.length ? _jsx("div", { className: "bt-inline wb-pack-list", "aria-label": t('wb.appearance.icons.imported'), children: choice.packs.map(pack => _jsx(Button, { size: "sm", tone: "ghost", onClick: () => void update({ ...choice, packs: choice.packs.filter(item => item.id !== pack.id), ...(choice.icons === pack.id ? { icons: undefined } : {}) }).then(() => notify(t('wb.appearance.icons.removed', { name: pack.name }))), children: t('wb.appearance.icons.remove', { name: pack.name }) }, pack.id)) }) : null, packReview && _jsx(IconPackReview, { ...packReview, replaces: !!choice.packs?.some(item => item.id === packReview.pack.id), onCancel: () => setPackReview(null), onInstall: () => { const { pack } = packReview; setPackReview(null); void update({ ...choice, packs: [...(choice.packs ?? []).filter(item => item.id !== pack.id), pack], icons: pack.id }).then(() => notify(t('wb.appearance.icons.installed', { name: pack.name }))); } })] }) }) : null, _jsx(Row, { label: t('wb.appearance.fonts'), hint: t('wb.appearance.fontsHint'), keywords: "typeface typography family font google fonts post text heading numbers code interface window dialogs", wide: true, children: _jsx(FontRoles, { font: effective.font, onRole: setRole, compact: true }) }), _jsx(Row, { label: t('wb.appearance.textSize'), hint: t('wb.appearance.textSizeHint'), keywords: "font scale bigger smaller zoom", children: _jsx(Slider, { label: t('wb.appearance.textSize'), min: 85, max: 120, value: Math.round(effective.font.scale * 100), format: v => formatPercent(v), onChange: v => void override({ font: { scale: v / 100 } }, false), onCommit: v => void override({ font: { scale: v / 100 } }) }) }), _jsx(Row, { label: t('wb.appearance.bold'), hint: t('wb.appearance.boldHint'), keywords: "font weight heavy", children: _jsx(Segmented, { label: t('wb.appearance.bold'), size: "sm", value: effective.font.bold >= 750 ? 800 : effective.font.bold >= 675 ? 700 : 600, onChange: bold => void override({ font: { bold } }), options: [{ value: 600, label: t('wb.appearance.bold.medium') }, { value: 700, label: t('wb.appearance.bold.bold') }, { value: 800, label: t('wb.appearance.bold.heavy') }] }) }), _jsx(Row, { label: t('wb.appearance.corners'), hint: t('wb.appearance.cornersHint'), keywords: "radius rounded square shape", children: _jsx(Segmented, { label: t('wb.appearance.corners'), size: "sm", value: cornerValue, onChange: value => { const corner = CORNERS.find(item => item.value === value); void override({ shape: { radius: corner.radius, button: corner.button } }); }, options: CORNERS.map(corner => ({ value: corner.value, label: t(corner.label) })) }) }), _jsx(Row, { label: t('wb.appearance.avatars'), keywords: "profile picture shape", children: _jsx(Segmented, { label: t('wb.appearance.avatars'), size: "sm", value: effective.shape.avatar, onChange: avatar => void override({ shape: { avatar } }), options: [{ value: 'circle', label: t('wb.appearance.avatars.circle') }, { value: 'rounded', label: t('wb.appearance.avatars.rounded') }, { value: 'square', label: t('wb.appearance.corners.square') }] }) }), _jsx(Row, { label: t('wb.appearance.density'), hint: t('wb.appearance.densityHint'), keywords: "compact spacing padding", children: _jsx(Segmented, { label: t('wb.appearance.density'), size: "sm", value: effective.layout.density, onChange: density => void override({ layout: { density } }), options: [{ value: 'compact', label: t('wb.appearance.density.compact') }, { value: 'default', label: t('wb.appearance.density.default') }, { value: 'comfortable', label: t('wb.appearance.density.roomy') }] }) }), _jsx(Row, { label: t('wb.appearance.timeline'), hint: t('wb.appearance.timelineHint'), keywords: "cards layout frame", children: _jsx(Segmented, { label: t('wb.appearance.timelineStyle'), size: "sm", value: timeline, onChange: value => void override({ layout: { cards: value === 'cards', frame: value === 'framed' } }), options: [{ value: 'flat', label: t('wb.appearance.timeline.flat') }, { value: 'framed', label: t('wb.appearance.timeline.framed') }, { value: 'cards', label: t('wb.appearance.timeline.cards') }] }) }), _jsx(Row, { label: t('wb.appearance.timelineWidth'), keywords: "column layout wide narrow", children: _jsx(Slider, { label: t('wb.appearance.timelineWidth'), min: 520, max: 820, step: 10, value: effective.layout.column, format: v => t('wb.appearance.px', { value: v }), onChange: column => void override({ layout: { column } }, false), onCommit: column => void override({ layout: { column } }) }) }), _jsx(Row, { label: t('wb.appearance.sidebarWidth'), keywords: "column layout trends", children: _jsx(Slider, { label: t('wb.appearance.sidebarWidth'), min: 290, max: 400, step: 10, value: effective.layout.sidebar, format: v => t('wb.appearance.px', { value: v }), onChange: sidebar => void override({ layout: { sidebar } }, false), onCommit: sidebar => void override({ layout: { sidebar } }) }) }), _jsx(Row, { label: t('wb.appearance.background'), hint: t('wb.appearance.backgroundHint'), keywords: "wallpaper pattern image photo canvas", children: _jsxs("div", { className: "bt-inline", children: [_jsx(Select, { label: t('wb.appearance.background'), value: backgroundChoice(effective.background), options: backgrounds(), width: 170, onChange: kind => { if (kind === 'image')
|
|
171
|
+
document.getElementById('bt-bg-file')?.click();
|
|
172
|
+
else
|
|
173
|
+
void override({ background: backgroundFor(kind, effective) }); } }), _jsx("input", { id: "bt-bg-file", type: "file", hidden: true, accept: "image/png,image/jpeg,image/webp,image/gif,image/avif", onChange: event => { void pickImage(event.target.files?.[0]); event.target.value = ''; } })] }) }), effective.background.kind === 'image' && _jsx(Row, { label: t('wb.appearance.dim'), hint: t('wb.appearance.dimHint'), keywords: "background image", children: _jsx(Slider, { label: t('wb.appearance.dim'), min: 35, max: 95, value: Math.round(effective.background.dim * 100), format: v => formatPercent(v), onChange: v => void override({ background: { ...effective.background, dim: v / 100 } }, false), onCommit: v => void override({ background: { ...effective.background, dim: v / 100 } }) }) }), _jsx(Row, { label: t('wb.appearance.motion'), hint: t('wb.appearance.motionHint'), keywords: "animation transition", children: _jsx(Segmented, { label: t('wb.appearance.motion'), size: "sm", value: effective.effects.motion === 0 ? 0 : effective.effects.motion < 200 ? 140 : 260, onChange: motion => void override({ effects: { motion } }), options: [{ value: 0, label: t('wb.common.off') }, { value: 140, label: t('wb.appearance.motion.subtle') }, { value: 260, label: t('wb.appearance.motion.lively') }] }) }), _jsx(Row, { label: t('wb.appearance.hover'), hint: t('wb.appearance.hoverHint'), keywords: "effect highlight lift glow", children: _jsx(Segmented, { label: t('wb.appearance.hoverEffect'), size: "sm", value: effective.effects.hover, onChange: hover => void override({ effects: { hover } }), options: [{ value: 'none', label: t('wb.appearance.hover.none') }, { value: 'tint', label: t('wb.appearance.hover.tint') }, { value: 'lift', label: t('wb.appearance.hover.lift') }, { value: 'glow', label: t('wb.appearance.bg.glow') }] }) }), _jsx(Row, { label: t('wb.appearance.crt'), hint: t('wb.appearance.crtHint'), keywords: "retro terminal effect", children: _jsx(Toggle, { label: t('wb.appearance.crt'), checked: effective.effects.crt, onChange: crt => void override({ effects: { crt } }) }) }), _jsx(ThemeCssEditor, { css: effective.css, onApply: text => { void override({ css: { text } }); notify(t('wb.appearance.cssApplied', { name: base.name })); } }, choice.preset)] }), _jsx(DoctorReport, { theme: effective }), _jsxs(Section, { title: t('wb.appearance.scopes'), id: "theme-scopes", hint: searching ? undefined : t('wb.appearance.scopesHint'), children: [_jsx(Row, { label: t('wb.appearance.chrome'), hint: t('wb.appearance.chromeHint'), keywords: "chrome window tabs titlebar panel colors own style", children: _jsx(Toggle, { label: t('wb.appearance.chrome'), checked: scopes.chrome === 'theme', onChange: on => void setScopes({ ...scopes, chrome: on ? 'theme' : 'own' }).catch(error => notify(getError(error), true)) }) }), _jsx(AccountThemes, { notify: notify }), _jsx(PaneThemes, { notify: notify })] }), _jsx(DownloadedFonts, { notify: notify }), (panelSite().appearance?.extra ?? []).map((Extra, index) => _jsx(Extra, { notify: notify, openSection: id => window.dispatchEvent(new CustomEvent('bt-panel-section', { detail: id })) }, index)), _jsx(CustomCssEditor, { notify: notify })] });
|
|
174
|
+
}
|
|
175
|
+
/** Theme choices for a scope row: follow (the level above) plus every theme with its swatch. */
|
|
176
|
+
/** The theme doctor's full report on the theme as it is now: every finding, where it is, what it found, how to fix it. Advice only. */
|
|
177
|
+
function DoctorReport({ theme }) {
|
|
178
|
+
const t = useT();
|
|
179
|
+
const advice = themeDoctor(theme);
|
|
180
|
+
const words = (item, part) => t(`wb.doctor.${item.key}.${part}`, item.params);
|
|
181
|
+
return _jsx(Section, { title: t('wb.doctor.title'), id: "theme-doctor", hint: t('wb.doctor.hint'), action: _jsx(Badge, { tone: advice.length ? undefined : 'ok', children: t('wb.doctor.count', { count: advice.length }) }), children: advice.length === 0
|
|
182
|
+
? _jsx("p", { className: "btp-hint", children: t('wb.doctor.empty') })
|
|
183
|
+
: _jsx("ul", { className: "bt-doctor", "aria-label": t('wb.doctor.title'), children: advice.map((item, index) => _jsxs("li", { className: `bt-doctor-item is-${item.kind}`, children: [_jsxs("span", { className: "bt-doctor-head", children: [_jsx(Badge, { children: t(`wb.doctor.kind.${item.kind}`) }), _jsx("strong", { children: words(item, 'found') })] }), _jsxs("small", { className: "bt-doctor-line", children: [t('wb.doctor.where'), ": ", _jsx("code", { children: item.where })] }), _jsxs("small", { className: "bt-doctor-line", children: [t('wb.doctor.fix'), ": ", words(item, 'fix')] })] }, `${item.id}:${item.where}:${index}`)) }) });
|
|
184
|
+
}
|
|
185
|
+
function scopeOptions(follow) {
|
|
186
|
+
// Called during render of components that use useT(), so the labels follow the language.
|
|
187
|
+
return [{ value: '', label: follow }, ...panelThemes().store.allThemes().map(theme => ({ value: theme.id, label: theme.name, icon: _jsx(ThemeDots, { theme: theme }) }))];
|
|
188
|
+
}
|
|
189
|
+
function AccountThemes({ notify }) {
|
|
190
|
+
const t = useT();
|
|
191
|
+
const { setScopes, themeName, themeState } = panelThemes().store;
|
|
192
|
+
const profiles = useProfiles();
|
|
193
|
+
const { scopes, choice } = useThemeState();
|
|
194
|
+
return _jsx(Row, { label: t('wb.panel.section.accounts'), hint: t('wb.appearance.accountsHint'), keywords: "account profile per account theme login", wide: true, children: _jsx("div", { className: "wb-scope-list", children: profiles.profiles.map(profile => _jsxs("div", { className: "wb-scope", children: [_jsxs("span", { className: "wb-scope-who", children: [_jsx(AccountAvatar, { profile: profile, size: 26 }), _jsxs("span", { children: [_jsx("b", { children: accountName(profile) }), _jsx("small", { children: scopes.profiles[profile.id] ? t('wb.appearance.ownTheme') : t('wb.appearance.followsApp', { name: themeName(choice.preset) }) })] })] }), _jsx(Select, { label: t('wb.appearance.themeFor', { name: accountName(profile) }), value: scopes.profiles[profile.id] ?? '', width: 210, options: scopeOptions(t('wb.appearance.followApp')), onChange: id => void setScopes(assign(themeState().scopes, 'profiles', profile.id, id || null)).catch(error => notify(getError(error), true)) })] }, profile.id)) }) });
|
|
195
|
+
}
|
|
196
|
+
/** Open site panes, each with the theme it shows and where that comes from. */
|
|
197
|
+
function PaneThemes({ notify }) {
|
|
198
|
+
const t = useT();
|
|
199
|
+
const { setScopes, tabTheme, themeName, themeState } = panelThemes().store;
|
|
200
|
+
const { scopes } = useThemeState();
|
|
201
|
+
const [, refresh] = useState(0);
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
const api = shell.api;
|
|
204
|
+
if (!api)
|
|
205
|
+
return;
|
|
206
|
+
const bump = () => refresh(n => n + 1);
|
|
207
|
+
const subs = [api.onDidAddPanel(bump), api.onDidRemovePanel(bump), api.onDidLayoutChange(bump)];
|
|
208
|
+
return () => subs.forEach(sub => sub.dispose());
|
|
209
|
+
}, []);
|
|
210
|
+
const panes = (shell.api?.panels ?? []).filter(panel => panel.params?.kind === 'web');
|
|
211
|
+
return _jsx(Row, { label: t('wb.appearance.panes'), hint: panes.length ? t('wb.appearance.panesHint') : t('wb.appearance.panesEmpty'), keywords: "pane split tab per pane theme", wide: true, children: panes.length > 0 && _jsx("div", { className: "wb-scope-list", children: panes.map(panel => {
|
|
212
|
+
const params = panel.params;
|
|
213
|
+
const profile = tabProfile(shell.profiles, params.profile);
|
|
214
|
+
const current = tabTheme({ id: panel.id, profile: profile.id });
|
|
215
|
+
return _jsxs("div", { className: "wb-scope", children: [_jsxs("span", { className: "wb-scope-who", children: [_jsx(ThemeDots, { theme: current.theme }), _jsxs("span", { children: [_jsx("b", { children: panel.api.title || params.url }), _jsxs("small", { children: [accountName(profile), " \u00B7 ", current.source === 'pane' ? t('wb.appearance.ownTheme') : current.source === 'account' ? t('wb.appearance.accountTheme', { name: themeName(current.id) }) : t('wb.appearance.appTheme', { name: themeName(current.id) })] })] })] }), _jsx(Select, { label: t('wb.appearance.themeFor', { name: panel.api.title || t('wb.appearance.pane') }), value: scopes.panes[panel.id] ?? '', width: 210, options: scopeOptions(t('wb.appearance.followAccount')), onChange: id => void setScopes(assign(themeState().scopes, 'panes', panel.id, id || null)).catch(error => notify(getError(error), true)) })] }, panel.id);
|
|
216
|
+
}) }) });
|
|
217
|
+
}
|
|
218
|
+
function DownloadedFonts({ notify }) {
|
|
219
|
+
const t = useT();
|
|
220
|
+
const { removeFont } = panelThemes().store;
|
|
221
|
+
const { fonts } = useThemeState();
|
|
222
|
+
const query = useSettingsQuery();
|
|
223
|
+
const title = t('wb.appearance.downloaded');
|
|
224
|
+
if (query && !`downloaded fonts google fonts typeface remove storage ${title}`.toLowerCase().includes(query.toLowerCase().trim()))
|
|
225
|
+
return null;
|
|
226
|
+
const total = fonts.reduce((sum, font) => sum + font.bytes, 0);
|
|
227
|
+
return _jsx(Section, { title: title, id: "fonts", hint: fonts.length ? t('wb.appearance.downloadedHint', { count: fonts.length, size: bytesLabel(total) }) : t('wb.appearance.downloadedEmpty'), children: _jsx(Row, { label: fonts.length ? t('wb.appearance.families') : t('wb.appearance.noneYet'), hint: t('wb.appearance.familiesHint'), keywords: "google fonts downloaded remove", wide: true, children: fonts.length > 0 && _jsx("ul", { className: "wb-fontlist", children: fonts.map(font => _jsxs("li", { children: [_jsxs("span", { children: [_jsx("b", { style: { fontFamily: `"${font.family}", system-ui` }, children: font.family }), _jsx("br", {}), _jsxs("small", { children: [weightsLabel(font.weights), " \u00B7 ", bytesLabel(font.bytes)] })] }), _jsx("small", { children: formatDate(font.installedAt, { dateStyle: 'medium' }) }), _jsx(Button, { size: "sm", tone: "ghost", onClick: () => void removeFont(font.family).then(() => notify(t('wb.appearance.removedFont', { family: font.family }))).catch(error => notify(getError(error), true)), children: t('wb.common.remove') })] }, font.family)) }) }) });
|
|
228
|
+
}
|
|
229
|
+
/** The selected theme's own CSS: travels with the theme (export, Save as theme); switching themes starts clean, like every customization. */
|
|
230
|
+
function ThemeCssEditor({ css, onApply }) {
|
|
231
|
+
const t = useT();
|
|
232
|
+
const [text, setText] = useState(css);
|
|
233
|
+
const query = useSettingsQuery();
|
|
234
|
+
useEffect(() => setText(css), [css]);
|
|
235
|
+
const label = t('wb.appearance.themeCss');
|
|
236
|
+
if (query && !`theme css stylesheet style code custom ${label}`.toLowerCase().includes(query.toLowerCase().trim()))
|
|
237
|
+
return null;
|
|
238
|
+
const dirty = text !== css;
|
|
239
|
+
return _jsx(Row, { label: label, hint: t('wb.appearance.themeCssHint'), keywords: "css stylesheet style code custom", wide: true, children: _jsxs("div", { className: "bt-code is-compact", style: { width: '100%' }, children: [_jsx("textarea", { "aria-label": t('wb.appearance.themeCssLabel'), spellCheck: false, value: text, placeholder: panelSite().cssExamples?.theme ?? '/* CSS that travels with this theme */', onChange: event => setText(event.target.value), onKeyDown: event => { if ((event.ctrlKey || event.metaKey) && event.key === 's') {
|
|
240
|
+
event.preventDefault();
|
|
241
|
+
if (dirty)
|
|
242
|
+
onApply(text);
|
|
243
|
+
} } }), _jsxs("div", { className: "bt-code-bar", children: [_jsx("small", { children: t('wb.appearance.cssLines', { count: text.split('\n').length }) }), dirty && _jsx(Button, { size: "sm", tone: "ghost", onClick: () => setText(css), children: t('wb.common.discard') }), _jsx(Button, { size: "sm", tone: "primary", disabled: !dirty, onClick: () => onApply(text), children: t('wb.common.apply') })] })] }) });
|
|
244
|
+
}
|
|
245
|
+
function Glyph({ d }) {
|
|
246
|
+
return _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", "aria-hidden": "true", children: _jsx("path", { d: d, fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
247
|
+
}
|
|
248
|
+
function ImportPanel({ onImport, onCancel }) {
|
|
249
|
+
const t = useT();
|
|
250
|
+
const [text, setText] = useState('');
|
|
251
|
+
const [error, setError] = useState('');
|
|
252
|
+
const file = useRef(null);
|
|
253
|
+
const run = (json) => {
|
|
254
|
+
const parsed = parseThemeJson(json);
|
|
255
|
+
if ('error' in parsed) {
|
|
256
|
+
setError(parsed.error);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
// The theme doctor: advice only (never a block); contrast is already in the warnings.
|
|
260
|
+
const hints = themeDoctor(parsed.theme).filter(advice => advice.kind !== 'contrast');
|
|
261
|
+
onImport(parsed.theme, hints.length ? [...parsed.warnings, t('wb.appearance.doctorHints', { count: hints.length, hint: t(`wb.doctor.${hints[0].key}.found`, hints[0].params) })] : parsed.warnings);
|
|
262
|
+
};
|
|
263
|
+
return _jsxs("div", { className: "bt-import", children: [_jsxs("div", { className: "bt-import-drop", onDragOver: event => event.preventDefault(), onDrop: event => { event.preventDefault(); void event.dataTransfer.files[0]?.text().then(run); }, children: [_jsx("strong", { children: t('wb.appearance.importTitle') }), _jsx("p", { children: t('wb.appearance.importText') }), _jsxs("div", { className: "bt-inline", children: [_jsx(Button, { size: "sm", tone: "primary", onClick: () => file.current?.click(), children: t('wb.common.chooseFile') }), _jsx(Button, { size: "sm", tone: "ghost", onClick: onCancel, children: t('wb.common.cancel') })] }), _jsx("input", { ref: file, type: "file", hidden: true, accept: "application/json,.json", onChange: event => { void event.target.files?.[0]?.text().then(run); event.target.value = ''; } })] }), _jsxs("div", { className: "bt-code is-compact", children: [_jsx("textarea", { "aria-label": t('wb.appearance.themeJson'), spellCheck: false, placeholder: `${t('wb.appearance.pasteJson')}\n{ "name": "My theme", "colors": { … } }`, value: text, onChange: event => { setText(event.target.value); setError(''); } }), _jsxs("div", { className: "bt-code-bar", children: [error ? _jsx("small", { className: "is-error", role: "alert", children: error }) : _jsx("small", { children: t('wb.appearance.importSafe') }), _jsx(Button, { size: "sm", disabled: !text.trim(), onClick: () => run(text), children: t('wb.appearance.importJson') })] })] })] });
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=Appearance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Appearance.js","sourceRoot":"","sources":["../../../../../../shell/src/panel/Appearance.tsx"],"names":[],"mappings":"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","sourcesContent":["// Appearance: the theme gallery (live previews rendered from each theme document), per-group\n// customization on top of the selected theme (fonts per role with the Google Fonts browser),\n// account and pane themes, downloaded fonts, import/export of theme JSON and Custom CSS. The theme\n// documents, the store and the miniature are the app's (`PanelSite.themes`).\nimport { useEffect, useRef, useState } from 'react';\nimport { THEME_SCHEMA_URL } from '../../../runtime/src/themeApi.ts';\nimport type { ThemeChoice } from '../../../runtime/src/themeChoice.ts';\nimport {\n FONT_CHOICES, MAX_IMAGE_CHARS, fontChoiceOf, googleFontsUsed, parseThemeJson, slug,\n type Background, type FontRole, type FontRoleName, type Pattern, type ThemeOverrides, type ThemeSpec,\n} from '../../../runtime/src/themeSpec.ts';\nimport { AccountAvatar, accountName, useProfiles } from '../frame/AccountSwitcher.tsx';\nimport { useT } from '../frame/hooks.ts';\nimport { formatDate, t, tx } from '../frame/i18n.ts';\nimport { ThemeDots } from '../frame/PaneTheme.tsx';\nimport { shell, type WebParams } from '../frame/state.ts';\nimport { assign } from '../frame/themeScopes.ts';\nimport { tabProfile } from '../profileModel.ts';\nimport { Badge, Button, ColorField, Row, Section, Segmented, Select, Slider, Toggle, useSettingsQuery, type Option } from './controls.tsx';\nimport { IconPackImport, IconPackReview } from './IconPackInstall.tsx';\nimport type { IconPack } from '../../../runtime/src/themeIcons.ts';\nimport { themeDoctor, type DoctorAdvice } from '../../../runtime/src/themeDoctor.ts';\nimport { bytesLabel, defaultWeights, loadCatalog, weightsLabel } from './fonts/catalog.ts';\nimport { FontRoles } from './fonts/FontRoles.tsx';\nimport { CustomCssEditor } from './Plugins.tsx';\nimport { panelSite, panelThemes, type Notify } from './site.ts';\nimport { useThemeState } from './themes.ts';\nimport './builder.css';\n\nconst getError = (error: unknown) => error instanceof Error ? error.message : String(error);\n\nconst CORNERS = [\n { value: 'square', label: 'wb.appearance.corners.square', radius: 0, button: 0 },\n { value: 'crisp', label: 'wb.appearance.corners.crisp', radius: 5, button: 5 },\n { value: 'soft', label: 'wb.appearance.corners.soft', radius: 12, button: 10 },\n { value: 'round', label: 'wb.appearance.corners.round', radius: 16, button: 9999 },\n] as const;\ntype BackgroundChoice = 'none' | 'glow' | Pattern | 'image';\nconst backgrounds = (): Array<Option<BackgroundChoice>> => [\n { value: 'none', label: t('wb.appearance.bg.none') }, { value: 'glow', label: t('wb.appearance.bg.glow') }, { value: 'dots', label: t('wb.appearance.bg.dots') }, { value: 'grid', label: t('wb.appearance.bg.grid') },\n { value: 'diagonal', label: t('wb.appearance.bg.diagonal') }, { value: 'scanlines', label: t('wb.appearance.bg.scanlines') }, { value: 'paper', label: t('wb.appearance.bg.paper') },\n { value: 'clouds', label: t('wb.appearance.bg.clouds') }, { value: 'image', label: t('wb.appearance.bg.image'), hint: t('wb.appearance.bg.imageHint') },\n];\n\nconst modeLabel = (theme: ThemeSpec) => theme.mode === 'auto' ? t('wb.appearance.mode.auto') : theme.mode === 'light' ? t('wb.appearance.mode.light') : t('wb.appearance.mode.dark');\nconst fontLabel = (theme: ThemeSpec) => {\n const family = theme.font.family;\n const choices = panelThemes().fontChoices ?? FONT_CHOICES;\n const choice = choices.find(item => item.id === fontChoiceOf(family, choices));\n return (choice?.key ? tx(choice.key, undefined, choice.label) : choice?.label) ?? family[0] ?? panelThemes().siteFont;\n};\n/** Built-in themes have translated descriptions (`theme.<id>.description` in the app's catalog); imported ones keep their own. */\nexport const themeDescription = (theme: ThemeSpec) => tx(`theme.${theme.id}.description`, undefined, theme.description);\nconst formatPercent = (value: number) => t('wb.appearance.percent', { value: value / 100 });\nconst hasOverrides = (choice: ThemeChoice) => !!choice.accent || Object.keys(choice.overrides).length > 0;\n\nfunction download(name: string, text: string) {\n const url = URL.createObjectURL(new Blob([text], { type: 'application/json' }));\n const anchor = document.createElement('a');\n anchor.href = url; anchor.download = name; anchor.click();\n setTimeout(() => URL.revokeObjectURL(url), 1000);\n}\n\nfunction backgroundFor(kind: BackgroundChoice, theme: ThemeSpec, image?: string): Background {\n const base = panelThemes().draftColors;\n const text = theme.colors?.text ?? '#8b98a5';\n const light = theme.mode === 'light';\n switch (kind) {\n case 'none': return { kind: 'none' };\n case 'glow': return { kind: 'gradient', from: theme.colors?.page ?? theme.colors?.bg ?? base.bg, to: theme.colors?.page ?? theme.colors?.bg ?? base.bg, angle: 180, glow: theme.colors?.accent ?? base.accent };\n case 'image': return { kind: 'image', url: image ?? '', fit: 'cover', dim: light ? 0.55 : 0.6 };\n case 'clouds': return { kind: 'pattern', pattern: 'clouds', ink: light ? '#ffffff' : text, opacity: light ? 0.55 : 0.07, size: 220 };\n case 'dots': return { kind: 'pattern', pattern: 'dots', ink: text, opacity: 0.16, size: 18 };\n case 'grid': return { kind: 'pattern', pattern: 'grid', ink: text, opacity: 0.06, size: 28 };\n case 'diagonal': return { kind: 'pattern', pattern: 'diagonal', ink: text, opacity: 0.06, size: 10 };\n case 'scanlines': return { kind: 'pattern', pattern: 'scanlines', ink: theme.colors?.accent ?? text, opacity: 0.05, size: 4 };\n case 'paper': return { kind: 'pattern', pattern: 'paper', ink: light ? '#7a6a50' : text, opacity: 0.1, size: 180 };\n }\n}\nconst backgroundChoice = (background: Background): BackgroundChoice =>\n background.kind === 'none' ? 'none' : background.kind === 'gradient' ? 'glow' : background.kind === 'image' ? 'image' : background.pattern;\n\n/** Asks the panel to show another section (the Theme Builder). */\nconst openSection = (section: string) => window.dispatchEvent(new CustomEvent('bt-panel-section', { detail: section }));\n\nexport function Appearance({ notify }: { notify: Notify }) {\n const t = useT();\n const themes = panelThemes();\n const { allThemes, installFont, missingFonts, setChoice, setScopes } = themes.store;\n const ThemePreview = themes.Preview;\n const { ready, choice, scopes } = useThemeState();\n const [importing, setImporting] = useState(false);\n const [asking, setAsking] = useState<{ theme: ThemeSpec; families: string[] } | null>(null);\n const [packReview, setPackReview] = useState<{ pack: IconPack; warnings: string[]; bytes: number } | null>(null);\n const query = useSettingsQuery();\n\n if (!ready) return null;\n const effective = themes.catalog.resolve(choice);\n const base = themes.catalog.base(choice);\n const all = allThemes(choice);\n const siteTheme = themes.catalog.defaultChoice.preset;\n const suffix = themes.fileSuffix ?? '.theme.json';\n\n const update = (next: ThemeChoice, commit = true) => setChoice(next, commit).catch(error => notify(getError(error), true));\n const override = (patch: ThemeOverrides, commit = true) => {\n const overrides: ThemeOverrides = { ...choice.overrides };\n for (const [key, value] of Object.entries(patch) as Array<[keyof ThemeOverrides, unknown]>) {\n (overrides as Record<string, unknown>)[key] = key === 'background' ? value : { ...(choice.overrides[key] as object | undefined), ...(value as object) };\n }\n return update({ ...choice, overrides }, commit);\n };\n const setRole = (role: FontRoleName, next: FontRole, commit = true) =>\n override({ font: { roles: { ...(choice.overrides.font?.roles ?? {}), [role]: next } } }, commit);\n\n function select(id: string) {\n if (id === choice.preset) return;\n // Customizations belong to the theme they were made on; switching starts clean.\n void update({ ...choice, preset: id, overrides: {}, accent: null });\n }\n function remove(theme: ThemeSpec) {\n const themes = choice.themes.filter(item => item.id !== theme.id);\n void update({ ...choice, themes, ...(choice.preset === theme.id ? { preset: siteTheme, overrides: {}, accent: null } : {}) }).then(() => notify(t('wb.appearance.removedTheme', { name: theme.name })));\n }\n function add(theme: ThemeSpec, message: string) {\n let id = theme.id;\n for (let n = 2; all.some(item => item.id === id); n++) id = `${theme.id.slice(0, 36)}-${n}`;\n void update({ ...choice, themes: [...choice.themes, { ...theme, id }], preset: id, overrides: {}, accent: null }).then(() => notify(message));\n }\n function exportTheme() {\n const custom = hasOverrides(choice);\n const doc: ThemeSpec = { ...effective, ...(custom ? { id: slug(`${effective.name} custom`), name: t('wb.appearance.customName', { name: effective.name }) } : {}) };\n // `$schema` lets editors validate and complete the file; imports ignore it.\n download(`${doc.id}${suffix}`, JSON.stringify({ $schema: THEME_SCHEMA_URL, ...doc }, null, 2));\n }\n function saveAsNew() {\n const name = t('wb.appearance.savedName', { name: base.name });\n add({ ...effective, id: slug(`${base.name} custom`), name, author: t('wb.appearance.you'), description: t('wb.appearance.basedOn', { name: base.name }) }, t('wb.appearance.saved', { name }));\n }\n /** An imported theme that names Google fonts asks before anything is downloaded. */\n function imported(theme: ThemeSpec, warnings: string[]) {\n setImporting(false);\n add(theme, `${t('wb.appearance.imported', { name: theme.name })}${warnings.length ? ` ${warnings.join(' ')}` : ''}`);\n const families = missingFonts(theme);\n if (families.length) setAsking({ theme, families });\n }\n async function downloadFonts(families: string[]) {\n setAsking(null);\n const catalog = await loadCatalog();\n for (const family of families) {\n const font = catalog.find(item => item.family === family);\n try {\n await installFont(family, font ? defaultWeights(font) : { kind: 'list', values: [400, 700] });\n notify(t('wb.appearance.downloadedFont', { family }));\n } catch (error) { notify(`${family}: ${getError(error)}`, true); }\n }\n }\n\n const cornerValue = CORNERS.find(corner => corner.radius === effective.shape.radius && corner.button === effective.shape.button)?.value ?? null;\n const timeline = effective.layout.cards ? 'cards' : effective.layout.frame ? 'framed' : 'flat';\n\n async function pickImage(file: File | undefined) {\n if (!file) return;\n if (!/^image\\/(png|jpeg|webp|gif|avif)$/.test(file.type)) { notify(t('wb.appearance.imageType'), true); return; }\n const url = await new Promise<string>((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(String(reader.result)); reader.onerror = () => reject(reader.error); reader.readAsDataURL(file); });\n if (url.length > MAX_IMAGE_CHARS) { notify(t('wb.appearance.imageTooLarge'), true); return; }\n void override({ background: backgroundFor('image', effective, url) });\n }\n\n const searching = !!query;\n return <>\n {!searching && <Section title={t('wb.appearance.theme')} id=\"themes\" hint={t('wb.appearance.themeHint')}\n action={<div className=\"bt-inline\">\n <Button size=\"sm\" tone=\"ghost\" onClick={() => setImporting(!importing)} icon={<Glyph d=\"M8 2v8m0 0L5 7m3 3 3-3M3 13h10\"/>}>{t('wb.common.import')}</Button>\n <Button size=\"sm\" tone=\"ghost\" onClick={exportTheme} icon={<Glyph d=\"M8 11V3m0 0L5 6m3-3 3 3M3 13h10\"/>}>{t('wb.common.export')}</Button>\n <Button size=\"sm\" tone=\"primary\" onClick={() => openSection('builder')} icon={<Glyph d=\"M3 13l.6-2.6L10.5 3.5l2 2-6.9 6.9zM9 5l2 2\"/>}>{t('wb.panel.section.builder')}</Button>\n </div>}>\n {importing && <ImportPanel onCancel={() => setImporting(false)} onImport={imported}/>}\n {asking && <div className=\"bt-import wb-ask\" role=\"alertdialog\" aria-label={t('wb.appearance.askFonts')}>\n <div className=\"bt-import-drop\">\n <strong>{t('wb.appearance.askFontsTitle', { name: asking.theme.name, fonts: asking.families.join(', ') })}</strong>\n <p>{t('wb.appearance.askFontsText', { count: asking.families.length })}</p>\n <div className=\"bt-inline\"><Button size=\"sm\" tone=\"primary\" onClick={() => void downloadFonts(asking.families)}>{t('wb.panel.updates.download')}</Button><Button size=\"sm\" tone=\"ghost\" onClick={() => setAsking(null)}>{t('wb.common.notNow')}</Button></div>\n </div>\n </div>}\n <div className=\"bt-gallery\" role=\"radiogroup\" aria-label={t('wb.appearance.theme')}>\n {all.map(theme => {\n const on = theme.id === choice.preset;\n const isImported = choice.themes.some(item => item.id === theme.id);\n return <div key={theme.id} className={`bt-theme ${on ? 'is-on' : ''}`}>\n <button type=\"button\" role=\"radio\" aria-checked={on} className=\"bt-theme-hit\" onClick={() => select(theme.id)} aria-label={`${theme.name}. ${themeDescription(theme)}`}>\n <ThemePreview theme={on ? effective : theme}/>\n <span className=\"bt-theme-info\">\n <span className=\"bt-theme-title\"><strong>{theme.name}</strong>{on && <span className=\"bt-theme-check\" aria-hidden=\"true\"><Glyph d=\"m4 8.5 2.5 2.5L12 5.5\"/></span>}</span>\n <small>{themeDescription(theme)}</small>\n <span className=\"bt-theme-tags\"><em>{modeLabel(theme)}</em><em>{fontLabel(theme)}</em>{theme.layout.cards && <em>{t('wb.appearance.timeline.cards')}</em>}{googleFontsUsed(theme).length > 0 && <em>Google Fonts</em>}{isImported && <em className=\"is-accent\">{t('wb.appearance.yours')}</em>}{theme.css && <em>CSS</em>}</span>\n </span>\n </button>\n {isImported && <button type=\"button\" className=\"bt-theme-remove\" aria-label={t('wb.appearance.removeNamed', { name: theme.name })} title={t('wb.appearance.removeTheme')} onClick={() => remove(theme)}><Glyph d=\"m4.5 4.5 7 7m0-7-7 7\"/></button>}\n </div>;\n })}\n </div>\n </Section>}\n\n <Section title={searching ? t('wb.appearance.theme') : t('wb.appearance.customize', { name: base.name })} id=\"customize\"\n hint={searching ? undefined : t('wb.appearance.customizeHint')}\n action={!searching && hasOverrides(choice) ? <div className=\"bt-inline\">\n <Button size=\"sm\" tone=\"ghost\" onClick={() => void update({ ...choice, overrides: {}, accent: null })}>{t('wb.common.reset')}</Button>\n <Button size=\"sm\" onClick={saveAsNew}>{t('wb.appearance.saveAsTheme')}</Button>\n </div> : undefined}>\n <Row label={t('wb.appearance.accent')} hint={t('wb.appearance.accentHint')} keywords=\"color colour highlight link\" wide>\n <ColorField label={t('wb.appearance.accentColor')} value={choice.accent} swatches={[...themes.accents]} autoLabel={t('wb.appearance.theme')} onChange={accent => void update({ ...choice, accent })}/>\n </Row>\n {themes.iconPacks?.length ? <Row label={t('wb.appearance.icons')} hint={t('wb.appearance.iconsHint')} keywords=\"icon pack glyphs symbols pixel import\" wide>\n <div className=\"wb-pack-row\"><div className=\"bt-inline\">\n <Select label={t('wb.appearance.icons')} value={choice.icons ?? 'theme'} width={220}\n onChange={icons => void update({ ...choice, icons: icons === 'theme' ? undefined : icons })}\n options={[{ value: 'theme', label: t('wb.appearance.icons.theme') }, { value: 'site', label: t('wb.appearance.icons.site') }, ...themes.iconPacks.filter(pack => !choice.packs?.some(item => item.id === pack.id)).map(pack => ({ value: pack.id, label: pack.name })), ...(choice.packs ?? []).map(pack => ({ value: pack.id, label: pack.name }))]}/>\n <IconPackImport onError={message => notify(message, true)} onParsed={(pack, warnings, bytes) => setPackReview({ pack, warnings, bytes })}/>\n </div>\n {choice.packs?.length ? <div className=\"bt-inline wb-pack-list\" aria-label={t('wb.appearance.icons.imported')}>{choice.packs.map(pack => <Button key={pack.id} size=\"sm\" tone=\"ghost\" onClick={() => void update({ ...choice, packs: choice.packs!.filter(item => item.id !== pack.id), ...(choice.icons === pack.id ? { icons: undefined } : {}) }).then(() => notify(t('wb.appearance.icons.removed', { name: pack.name })))}>{t('wb.appearance.icons.remove', { name: pack.name })}</Button>)}</div> : null}\n {packReview && <IconPackReview {...packReview} replaces={!!choice.packs?.some(item => item.id === packReview.pack.id)} onCancel={() => setPackReview(null)}\n onInstall={() => { const { pack } = packReview; setPackReview(null); void update({ ...choice, packs: [...(choice.packs ?? []).filter(item => item.id !== pack.id), pack], icons: pack.id }).then(() => notify(t('wb.appearance.icons.installed', { name: pack.name }))); }}/>}</div>\n </Row> : null}\n <Row label={t('wb.appearance.fonts')} hint={t('wb.appearance.fontsHint')}\n keywords=\"typeface typography family font google fonts post text heading numbers code interface window dialogs\" wide>\n <FontRoles font={effective.font} onRole={setRole} compact/>\n </Row>\n <Row label={t('wb.appearance.textSize')} hint={t('wb.appearance.textSizeHint')} keywords=\"font scale bigger smaller zoom\">\n <Slider label={t('wb.appearance.textSize')} min={85} max={120} value={Math.round(effective.font.scale * 100)} format={v => formatPercent(v)}\n onChange={v => void override({ font: { scale: v / 100 } }, false)} onCommit={v => void override({ font: { scale: v / 100 } })}/>\n </Row>\n <Row label={t('wb.appearance.bold')} hint={t('wb.appearance.boldHint')} keywords=\"font weight heavy\">\n <Segmented label={t('wb.appearance.bold')} size=\"sm\" value={effective.font.bold >= 750 ? 800 : effective.font.bold >= 675 ? 700 : 600}\n onChange={bold => void override({ font: { bold } })} options={[{ value: 600, label: t('wb.appearance.bold.medium') }, { value: 700, label: t('wb.appearance.bold.bold') }, { value: 800, label: t('wb.appearance.bold.heavy') }]}/>\n </Row>\n <Row label={t('wb.appearance.corners')} hint={t('wb.appearance.cornersHint')} keywords=\"radius rounded square shape\">\n <Segmented label={t('wb.appearance.corners')} size=\"sm\" value={cornerValue} onChange={value => { const corner = CORNERS.find(item => item.value === value)!; void override({ shape: { radius: corner.radius, button: corner.button } }); }}\n options={CORNERS.map(corner => ({ value: corner.value, label: t(corner.label) }))}/>\n </Row>\n <Row label={t('wb.appearance.avatars')} keywords=\"profile picture shape\">\n <Segmented label={t('wb.appearance.avatars')} size=\"sm\" value={effective.shape.avatar} onChange={avatar => void override({ shape: { avatar } })}\n options={[{ value: 'circle', label: t('wb.appearance.avatars.circle') }, { value: 'rounded', label: t('wb.appearance.avatars.rounded') }, { value: 'square', label: t('wb.appearance.corners.square') }]}/>\n </Row>\n <Row label={t('wb.appearance.density')} hint={t('wb.appearance.densityHint')} keywords=\"compact spacing padding\">\n <Segmented label={t('wb.appearance.density')} size=\"sm\" value={effective.layout.density} onChange={density => void override({ layout: { density } })}\n options={[{ value: 'compact', label: t('wb.appearance.density.compact') }, { value: 'default', label: t('wb.appearance.density.default') }, { value: 'comfortable', label: t('wb.appearance.density.roomy') }]}/>\n </Row>\n <Row label={t('wb.appearance.timeline')} hint={t('wb.appearance.timelineHint')} keywords=\"cards layout frame\">\n <Segmented label={t('wb.appearance.timelineStyle')} size=\"sm\" value={timeline} onChange={value => void override({ layout: { cards: value === 'cards', frame: value === 'framed' } })}\n options={[{ value: 'flat', label: t('wb.appearance.timeline.flat') }, { value: 'framed', label: t('wb.appearance.timeline.framed') }, { value: 'cards', label: t('wb.appearance.timeline.cards') }]}/>\n </Row>\n <Row label={t('wb.appearance.timelineWidth')} keywords=\"column layout wide narrow\">\n <Slider label={t('wb.appearance.timelineWidth')} min={520} max={820} step={10} value={effective.layout.column} format={v => t('wb.appearance.px', { value: v })}\n onChange={column => void override({ layout: { column } }, false)} onCommit={column => void override({ layout: { column } })}/>\n </Row>\n <Row label={t('wb.appearance.sidebarWidth')} keywords=\"column layout trends\">\n <Slider label={t('wb.appearance.sidebarWidth')} min={290} max={400} step={10} value={effective.layout.sidebar} format={v => t('wb.appearance.px', { value: v })}\n onChange={sidebar => void override({ layout: { sidebar } }, false)} onCommit={sidebar => void override({ layout: { sidebar } })}/>\n </Row>\n <Row label={t('wb.appearance.background')} hint={t('wb.appearance.backgroundHint')} keywords=\"wallpaper pattern image photo canvas\">\n <div className=\"bt-inline\">\n <Select label={t('wb.appearance.background')} value={backgroundChoice(effective.background)} options={backgrounds()} width={170}\n onChange={kind => { if (kind === 'image') document.getElementById('bt-bg-file')?.click(); else void override({ background: backgroundFor(kind, effective) }); }}/>\n <input id=\"bt-bg-file\" type=\"file\" hidden accept=\"image/png,image/jpeg,image/webp,image/gif,image/avif\" onChange={event => { void pickImage(event.target.files?.[0]); event.target.value = ''; }}/>\n </div>\n </Row>\n {effective.background.kind === 'image' && <Row label={t('wb.appearance.dim')} hint={t('wb.appearance.dimHint')} keywords=\"background image\">\n <Slider label={t('wb.appearance.dim')} min={35} max={95} value={Math.round(effective.background.dim * 100)} format={v => formatPercent(v)}\n onChange={v => void override({ background: { ...(effective.background as Extract<Background, { kind: 'image' }>), dim: v / 100 } }, false)}\n onCommit={v => void override({ background: { ...(effective.background as Extract<Background, { kind: 'image' }>), dim: v / 100 } })}/>\n </Row>}\n <Row label={t('wb.appearance.motion')} hint={t('wb.appearance.motionHint')} keywords=\"animation transition\">\n <Segmented label={t('wb.appearance.motion')} size=\"sm\" value={effective.effects.motion === 0 ? 0 : effective.effects.motion < 200 ? 140 : 260} onChange={motion => void override({ effects: { motion } })}\n options={[{ value: 0, label: t('wb.common.off') }, { value: 140, label: t('wb.appearance.motion.subtle') }, { value: 260, label: t('wb.appearance.motion.lively') }]}/>\n </Row>\n <Row label={t('wb.appearance.hover')} hint={t('wb.appearance.hoverHint')} keywords=\"effect highlight lift glow\">\n <Segmented label={t('wb.appearance.hoverEffect')} size=\"sm\" value={effective.effects.hover} onChange={hover => void override({ effects: { hover } })}\n options={[{ value: 'none', label: t('wb.appearance.hover.none') }, { value: 'tint', label: t('wb.appearance.hover.tint') }, { value: 'lift', label: t('wb.appearance.hover.lift') }, { value: 'glow', label: t('wb.appearance.bg.glow') }]}/>\n </Row>\n <Row label={t('wb.appearance.crt')} hint={t('wb.appearance.crtHint')} keywords=\"retro terminal effect\">\n <Toggle label={t('wb.appearance.crt')} checked={effective.effects.crt} onChange={crt => void override({ effects: { crt } })}/>\n </Row>\n <ThemeCssEditor key={choice.preset} css={effective.css} onApply={text => { void override({ css: { text } }); notify(t('wb.appearance.cssApplied', { name: base.name })); }}/>\n </Section>\n\n <DoctorReport theme={effective}/>\n\n <Section title={t('wb.appearance.scopes')} id=\"theme-scopes\" hint={searching ? undefined : t('wb.appearance.scopesHint')}>\n <Row label={t('wb.appearance.chrome')} hint={t('wb.appearance.chromeHint')}\n keywords=\"chrome window tabs titlebar panel colors own style\">\n <Toggle label={t('wb.appearance.chrome')} checked={scopes.chrome === 'theme'} onChange={on => void setScopes({ ...scopes, chrome: on ? 'theme' : 'own' }).catch(error => notify(getError(error), true))}/>\n </Row>\n <AccountThemes notify={notify}/>\n <PaneThemes notify={notify}/>\n </Section>\n\n <DownloadedFonts notify={notify}/>\n {(panelSite().appearance?.extra ?? []).map((Extra, index) => <Extra key={index} notify={notify} openSection={id => window.dispatchEvent(new CustomEvent('bt-panel-section', { detail: id }))}/>)}\n <CustomCssEditor notify={notify}/>\n </>;\n}\n\n/** Theme choices for a scope row: follow (the level above) plus every theme with its swatch. */\n/** The theme doctor's full report on the theme as it is now: every finding, where it is, what it found, how to fix it. Advice only. */\nfunction DoctorReport({ theme }: { theme: ThemeSpec }) {\n const t = useT();\n const advice = themeDoctor(theme);\n const words = (item: DoctorAdvice, part: 'found' | 'fix') => t(`wb.doctor.${item.key}.${part}`, item.params);\n return <Section title={t('wb.doctor.title')} id=\"theme-doctor\" hint={t('wb.doctor.hint')} action={<Badge tone={advice.length ? undefined : 'ok'}>{t('wb.doctor.count', { count: advice.length })}</Badge>}>\n {advice.length === 0\n ? <p className=\"btp-hint\">{t('wb.doctor.empty')}</p>\n : <ul className=\"bt-doctor\" aria-label={t('wb.doctor.title')}>\n {advice.map((item, index) => <li key={`${item.id}:${item.where}:${index}`} className={`bt-doctor-item is-${item.kind}`}>\n <span className=\"bt-doctor-head\"><Badge>{t(`wb.doctor.kind.${item.kind}`)}</Badge><strong>{words(item, 'found')}</strong></span>\n <small className=\"bt-doctor-line\">{t('wb.doctor.where')}: <code>{item.where}</code></small>\n <small className=\"bt-doctor-line\">{t('wb.doctor.fix')}: {words(item, 'fix')}</small>\n </li>)}\n </ul>}\n </Section>;\n}\n\nfunction scopeOptions(follow: string): Array<Option<string>> {\n // Called during render of components that use useT(), so the labels follow the language.\n return [{ value: '', label: follow }, ...panelThemes().store.allThemes().map(theme => ({ value: theme.id, label: theme.name, icon: <ThemeDots theme={theme}/> }))];\n}\n\nfunction AccountThemes({ notify }: { notify: Notify }) {\n const t = useT();\n const { setScopes, themeName, themeState } = panelThemes().store;\n const profiles = useProfiles();\n const { scopes, choice } = useThemeState();\n return <Row label={t('wb.panel.section.accounts')} hint={t('wb.appearance.accountsHint')} keywords=\"account profile per account theme login\" wide>\n <div className=\"wb-scope-list\">\n {profiles.profiles.map(profile => <div key={profile.id} className=\"wb-scope\">\n <span className=\"wb-scope-who\"><AccountAvatar profile={profile} size={26}/><span><b>{accountName(profile)}</b><small>{scopes.profiles[profile.id] ? t('wb.appearance.ownTheme') : t('wb.appearance.followsApp', { name: themeName(choice.preset) })}</small></span></span>\n <Select label={t('wb.appearance.themeFor', { name: accountName(profile) })} value={scopes.profiles[profile.id] ?? ''} width={210} options={scopeOptions(t('wb.appearance.followApp'))}\n onChange={id => void setScopes(assign(themeState().scopes, 'profiles', profile.id, id || null)).catch(error => notify(getError(error), true))}/>\n </div>)}\n </div>\n </Row>;\n}\n\n/** Open site panes, each with the theme it shows and where that comes from. */\nfunction PaneThemes({ notify }: { notify: Notify }) {\n const t = useT();\n const { setScopes, tabTheme, themeName, themeState } = panelThemes().store;\n const { scopes } = useThemeState();\n const [, refresh] = useState(0);\n useEffect(() => {\n const api = shell.api;\n if (!api) return;\n const bump = () => refresh(n => n + 1);\n const subs = [api.onDidAddPanel(bump), api.onDidRemovePanel(bump), api.onDidLayoutChange(bump)];\n return () => subs.forEach(sub => sub.dispose());\n }, []);\n const panes = (shell.api?.panels ?? []).filter(panel => (panel.params as WebParams | undefined)?.kind === 'web');\n return <Row label={t('wb.appearance.panes')} hint={panes.length ? t('wb.appearance.panesHint') : t('wb.appearance.panesEmpty')} keywords=\"pane split tab per pane theme\" wide>\n {panes.length > 0 && <div className=\"wb-scope-list\">\n {panes.map(panel => {\n const params = panel.params as WebParams;\n const profile = tabProfile(shell.profiles, params.profile);\n const current = tabTheme({ id: panel.id, profile: profile.id });\n return <div key={panel.id} className=\"wb-scope\">\n <span className=\"wb-scope-who\"><ThemeDots theme={current.theme}/><span><b>{panel.api.title || params.url}</b><small>{accountName(profile)} · {current.source === 'pane' ? t('wb.appearance.ownTheme') : current.source === 'account' ? t('wb.appearance.accountTheme', { name: themeName(current.id) }) : t('wb.appearance.appTheme', { name: themeName(current.id) })}</small></span></span>\n <Select label={t('wb.appearance.themeFor', { name: panel.api.title || t('wb.appearance.pane') })} value={scopes.panes[panel.id] ?? ''} width={210} options={scopeOptions(t('wb.appearance.followAccount'))}\n onChange={id => void setScopes(assign(themeState().scopes, 'panes', panel.id, id || null)).catch(error => notify(getError(error), true))}/>\n </div>;\n })}\n </div>}\n </Row>;\n}\n\nfunction DownloadedFonts({ notify }: { notify: Notify }) {\n const t = useT();\n const { removeFont } = panelThemes().store;\n const { fonts } = useThemeState();\n const query = useSettingsQuery();\n const title = t('wb.appearance.downloaded');\n if (query && !`downloaded fonts google fonts typeface remove storage ${title}`.toLowerCase().includes(query.toLowerCase().trim())) return null;\n const total = fonts.reduce((sum, font) => sum + font.bytes, 0);\n return <Section title={title} id=\"fonts\" hint={fonts.length ? t('wb.appearance.downloadedHint', { count: fonts.length, size: bytesLabel(total) }) : t('wb.appearance.downloadedEmpty')}>\n <Row label={fonts.length ? t('wb.appearance.families') : t('wb.appearance.noneYet')} hint={t('wb.appearance.familiesHint')} keywords=\"google fonts downloaded remove\" wide>\n {fonts.length > 0 && <ul className=\"wb-fontlist\">\n {fonts.map(font => <li key={font.family}>\n <span><b style={{ fontFamily: `\"${font.family}\", system-ui` }}>{font.family}</b><br/><small>{weightsLabel(font.weights)} · {bytesLabel(font.bytes)}</small></span>\n <small>{formatDate(font.installedAt, { dateStyle: 'medium' })}</small>\n <Button size=\"sm\" tone=\"ghost\" onClick={() => void removeFont(font.family).then(() => notify(t('wb.appearance.removedFont', { family: font.family }))).catch(error => notify(getError(error), true))}>{t('wb.common.remove')}</Button>\n </li>)}\n </ul>}\n </Row>\n </Section>;\n}\n\n/** The selected theme's own CSS: travels with the theme (export, Save as theme); switching themes starts clean, like every customization. */\nfunction ThemeCssEditor({ css, onApply }: { css: string; onApply(text: string): void }) {\n const t = useT();\n const [text, setText] = useState(css);\n const query = useSettingsQuery();\n useEffect(() => setText(css), [css]);\n const label = t('wb.appearance.themeCss');\n if (query && !`theme css stylesheet style code custom ${label}`.toLowerCase().includes(query.toLowerCase().trim())) return null;\n const dirty = text !== css;\n return <Row label={label} hint={t('wb.appearance.themeCssHint')} keywords=\"css stylesheet style code custom\" wide>\n <div className=\"bt-code is-compact\" style={{ width: '100%' }}>\n <textarea aria-label={t('wb.appearance.themeCssLabel')} spellCheck={false} value={text} placeholder={panelSite().cssExamples?.theme ?? '/* CSS that travels with this theme */'}\n onChange={event => setText(event.target.value)}\n onKeyDown={event => { if ((event.ctrlKey || event.metaKey) && event.key === 's') { event.preventDefault(); if (dirty) onApply(text); } }}/>\n <div className=\"bt-code-bar\">\n <small>{t('wb.appearance.cssLines', { count: text.split('\\n').length })}</small>\n {dirty && <Button size=\"sm\" tone=\"ghost\" onClick={() => setText(css)}>{t('wb.common.discard')}</Button>}\n <Button size=\"sm\" tone=\"primary\" disabled={!dirty} onClick={() => onApply(text)}>{t('wb.common.apply')}</Button>\n </div>\n </div>\n </Row>;\n}\n\nfunction Glyph({ d }: { d: string }) {\n return <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d={d} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\"/></svg>;\n}\n\nfunction ImportPanel({ onImport, onCancel }: { onImport(theme: ThemeSpec, warnings: string[]): void; onCancel(): void }) {\n const t = useT();\n const [text, setText] = useState('');\n const [error, setError] = useState('');\n const file = useRef<HTMLInputElement>(null);\n const run = (json: string) => {\n const parsed = parseThemeJson(json);\n if ('error' in parsed) { setError(parsed.error); return; }\n // The theme doctor: advice only (never a block); contrast is already in the warnings.\n const hints = themeDoctor(parsed.theme).filter(advice => advice.kind !== 'contrast');\n onImport(parsed.theme, hints.length ? [...parsed.warnings, t('wb.appearance.doctorHints', { count: hints.length, hint: t(`wb.doctor.${hints[0]!.key}.found`, hints[0]!.params) })] : parsed.warnings);\n };\n return <div className=\"bt-import\">\n <div className=\"bt-import-drop\" onDragOver={event => event.preventDefault()}\n onDrop={event => { event.preventDefault(); void event.dataTransfer.files[0]?.text().then(run); }}>\n <strong>{t('wb.appearance.importTitle')}</strong>\n <p>{t('wb.appearance.importText')}</p>\n <div className=\"bt-inline\"><Button size=\"sm\" tone=\"primary\" onClick={() => file.current?.click()}>{t('wb.common.chooseFile')}</Button><Button size=\"sm\" tone=\"ghost\" onClick={onCancel}>{t('wb.common.cancel')}</Button></div>\n <input ref={file} type=\"file\" hidden accept=\"application/json,.json\" onChange={event => { void event.target.files?.[0]?.text().then(run); event.target.value = ''; }}/>\n </div>\n <div className=\"bt-code is-compact\">\n <textarea aria-label={t('wb.appearance.themeJson')} spellCheck={false} placeholder={`${t('wb.appearance.pasteJson')}\\n{ \"name\": \"My theme\", \"colors\": { … } }`} value={text} onChange={event => { setText(event.target.value); setError(''); }}/>\n <div className=\"bt-code-bar\">\n {error ? <small className=\"is-error\" role=\"alert\">{error}</small> : <small>{t('wb.appearance.importSafe')}</small>}\n <Button size=\"sm\" disabled={!text.trim()} onClick={() => run(text)}>{t('wb.appearance.importJson')}</Button>\n </div>\n </div>\n </div>;\n}\n\n"]}
|