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
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type ColorRole, type RoleColors } from './themeComponents.ts';
|
|
2
|
+
export declare const DIVIDER_STYLES: readonly ["none", "hairline", "solid", "dashed", "dotted", "double"];
|
|
3
|
+
export declare const CHROME_KINDS: readonly ["none", "titlebar", "masthead", "prompt"];
|
|
4
|
+
export declare const RING_STYLES: readonly ["solid", "dashed", "dotted", "double"];
|
|
5
|
+
export declare const MOTION_CURVES: readonly ["standard", "snappy", "spring", "linear", "steps"];
|
|
6
|
+
export declare const LINK_UNDERLINES: readonly ["always", "hover", "never"];
|
|
7
|
+
export type ThemeDecor = {
|
|
8
|
+
dividers?: {
|
|
9
|
+
style: typeof DIVIDER_STYLES[number];
|
|
10
|
+
color?: ColorRole;
|
|
11
|
+
width?: number;
|
|
12
|
+
};
|
|
13
|
+
/** A drawn frame around the main column: a window title bar, a newspaper masthead, a terminal prompt. `title` is plain text. */
|
|
14
|
+
chrome?: {
|
|
15
|
+
kind: typeof CHROME_KINDS[number];
|
|
16
|
+
title?: string;
|
|
17
|
+
};
|
|
18
|
+
focusRing?: {
|
|
19
|
+
width?: number;
|
|
20
|
+
style?: typeof RING_STYLES[number];
|
|
21
|
+
color?: ColorRole;
|
|
22
|
+
offset?: number;
|
|
23
|
+
};
|
|
24
|
+
selection?: {
|
|
25
|
+
fill: ColorRole;
|
|
26
|
+
text: ColorRole;
|
|
27
|
+
};
|
|
28
|
+
scrollbar?: {
|
|
29
|
+
width?: 'auto' | 'thin';
|
|
30
|
+
thumb?: ColorRole;
|
|
31
|
+
track?: ColorRole;
|
|
32
|
+
style?: 'flat' | 'classic';
|
|
33
|
+
};
|
|
34
|
+
links?: {
|
|
35
|
+
underline: typeof LINK_UNDERLINES[number];
|
|
36
|
+
};
|
|
37
|
+
motion?: {
|
|
38
|
+
duration?: number;
|
|
39
|
+
curve?: typeof MOTION_CURVES[number];
|
|
40
|
+
press?: number;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
/** Text a theme may put into a drawn bar: letters, digits, spaces and a little punctuation; it is written into a CSS string. */
|
|
44
|
+
export declare const chromeTitle: (value: unknown) => string;
|
|
45
|
+
/** The `decor` group from JSON. Null when nothing valid is left. */
|
|
46
|
+
export declare function sanitizeDecor(value: unknown): ThemeDecor | null;
|
|
47
|
+
/** Where a site's decoration goes. Every entry is optional: a site without it draws nothing for that key. */
|
|
48
|
+
export type DecorTargets<Context> = {
|
|
49
|
+
/** Rows whose bottom edge is the divider between items (a site's list cells). */
|
|
50
|
+
divider?: string;
|
|
51
|
+
/** Links inside running text. */
|
|
52
|
+
link?: string;
|
|
53
|
+
/** What takes keyboard focus. */
|
|
54
|
+
focusable?: string;
|
|
55
|
+
/** What moves with `motion` (buttons, links, rows). */
|
|
56
|
+
moving?: string;
|
|
57
|
+
/** What a press shrinks. */
|
|
58
|
+
pressable?: string;
|
|
59
|
+
/** The scrollable roots. */
|
|
60
|
+
scroller?: string;
|
|
61
|
+
/** The site's drawing of each chrome kind. */
|
|
62
|
+
chrome?: Partial<Record<Exclude<typeof CHROME_KINDS[number], 'none'>, (title: string, ctx: Context) => string>>;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* CSS for a theme's decoration. A focus ring is always drawn when the theme names one (at least 2px
|
|
66
|
+
* and 3:1 on the page's surfaces: the color is swapped for a visible one otherwise); motion only
|
|
67
|
+
* for people who have not asked for less of it.
|
|
68
|
+
*/
|
|
69
|
+
export declare function compileDecor<Context extends {
|
|
70
|
+
colors: RoleColors;
|
|
71
|
+
}>(decor: ThemeDecor, targets: DecorTargets<Context>, ctx: Context): string[];
|
|
72
|
+
/** A theme's text as a CSS string literal (for `content`): the allow-list of `chromeTitle` plus escaping of what could end the string. */
|
|
73
|
+
export declare const cssString: (value: string) => string;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// Decoration: what a theme draws between and around the components: divider lines, a title bar or a
|
|
2
|
+
// masthead, the focus ring, selection, scrollbars, link underlines, the feel of motion. Fixed words
|
|
3
|
+
// and clamped numbers, colors by role. Where the lines and bars go is the site's (its decor targets).
|
|
4
|
+
// Pure.
|
|
5
|
+
import { contrastRatio } from "./themeApi.js";
|
|
6
|
+
import { COLOR_ROLES } from "./themeComponents.js";
|
|
7
|
+
export const DIVIDER_STYLES = ['none', 'hairline', 'solid', 'dashed', 'dotted', 'double'];
|
|
8
|
+
export const CHROME_KINDS = ['none', 'titlebar', 'masthead', 'prompt'];
|
|
9
|
+
export const RING_STYLES = ['solid', 'dashed', 'dotted', 'double'];
|
|
10
|
+
export const MOTION_CURVES = ['standard', 'snappy', 'spring', 'linear', 'steps'];
|
|
11
|
+
export const LINK_UNDERLINES = ['always', 'hover', 'never'];
|
|
12
|
+
const obj = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
13
|
+
const oneOf = (value, options) => options.includes(value) ? value : undefined;
|
|
14
|
+
const num = (value, min, max) => typeof value === 'number' && Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : undefined;
|
|
15
|
+
const role = (value) => oneOf(value, COLOR_ROLES);
|
|
16
|
+
/** Text a theme may put into a drawn bar: letters, digits, spaces and a little punctuation; it is written into a CSS string. */
|
|
17
|
+
export const chromeTitle = (value) => typeof value === 'string' ? value.replace(/[^\p{L}\p{N} .,:!?&+\-_/#@*~()[\]|>$]/gu, '').replace(/&/g, '+').trim().slice(0, 24) : '';
|
|
18
|
+
/** The `decor` group from JSON. Null when nothing valid is left. */
|
|
19
|
+
export function sanitizeDecor(value) {
|
|
20
|
+
const source = obj(value);
|
|
21
|
+
const out = {};
|
|
22
|
+
const dividers = obj(source.dividers), dividerStyle = oneOf(dividers.style, DIVIDER_STYLES);
|
|
23
|
+
if (dividerStyle) {
|
|
24
|
+
const color = role(dividers.color), width = num(dividers.width, 0, 3);
|
|
25
|
+
out.dividers = { style: dividerStyle, ...(color ? { color } : {}), ...(width !== undefined ? { width: +width.toFixed(1) } : {}) };
|
|
26
|
+
}
|
|
27
|
+
const chrome = obj(source.chrome), kind = oneOf(chrome.kind, CHROME_KINDS);
|
|
28
|
+
if (kind && kind !== 'none') {
|
|
29
|
+
const title = chromeTitle(chrome.title);
|
|
30
|
+
out.chrome = { kind, ...(title ? { title } : {}) };
|
|
31
|
+
}
|
|
32
|
+
const ring = obj(source.focusRing);
|
|
33
|
+
if (Object.keys(ring).length) {
|
|
34
|
+
const width = num(ring.width, 2, 4), style = oneOf(ring.style, RING_STYLES), color = role(ring.color), offset = num(ring.offset, 0, 4);
|
|
35
|
+
const focusRing = { ...(width !== undefined ? { width: Math.round(width) } : {}), ...(style ? { style } : {}), ...(color ? { color } : {}), ...(offset !== undefined ? { offset: Math.round(offset) } : {}) };
|
|
36
|
+
if (Object.keys(focusRing).length)
|
|
37
|
+
out.focusRing = focusRing;
|
|
38
|
+
}
|
|
39
|
+
const selection = obj(source.selection), fill = role(selection.fill), text = role(selection.text);
|
|
40
|
+
if (fill && text)
|
|
41
|
+
out.selection = { fill, text };
|
|
42
|
+
const bar = obj(source.scrollbar);
|
|
43
|
+
if (Object.keys(bar).length) {
|
|
44
|
+
const width = oneOf(bar.width, ['auto', 'thin']), thumb = role(bar.thumb), track = role(bar.track), style = oneOf(bar.style, ['flat', 'classic']);
|
|
45
|
+
const scrollbar = { ...(width ? { width } : {}), ...(thumb ? { thumb } : {}), ...(track ? { track } : {}), ...(style ? { style } : {}) };
|
|
46
|
+
if (Object.keys(scrollbar).length)
|
|
47
|
+
out.scrollbar = scrollbar;
|
|
48
|
+
}
|
|
49
|
+
const underline = oneOf(obj(source.links).underline, LINK_UNDERLINES);
|
|
50
|
+
if (underline)
|
|
51
|
+
out.links = { underline };
|
|
52
|
+
const motion = obj(source.motion);
|
|
53
|
+
if (Object.keys(motion).length) {
|
|
54
|
+
const duration = num(motion.duration, 0, 400), curve = oneOf(motion.curve, MOTION_CURVES), press = num(motion.press, 0.96, 1);
|
|
55
|
+
const value = { ...(duration !== undefined ? { duration: Math.round(duration) } : {}), ...(curve ? { curve } : {}), ...(press !== undefined ? { press: +press.toFixed(3) } : {}) };
|
|
56
|
+
if (Object.keys(value).length)
|
|
57
|
+
out.motion = value;
|
|
58
|
+
}
|
|
59
|
+
return Object.keys(out).length ? out : null;
|
|
60
|
+
}
|
|
61
|
+
const CURVES = {
|
|
62
|
+
standard: 'cubic-bezier(.2,.7,.2,1)', snappy: 'cubic-bezier(.3,1.4,.5,1)', spring: 'cubic-bezier(.2,1.6,.4,1)', linear: 'linear', steps: 'steps(3,end)',
|
|
63
|
+
};
|
|
64
|
+
/** The role among `candidates` that reaches `ratio` on every surface, else the most visible one. */
|
|
65
|
+
function visibleOn(colors, wanted, surfaces, ratio) {
|
|
66
|
+
const worst = (hex) => Math.min(...surfaces.map(surface => contrastRatio(hex, surface)));
|
|
67
|
+
if (worst(colors[wanted]) >= ratio)
|
|
68
|
+
return colors[wanted];
|
|
69
|
+
return ['accent', 'text', 'inverse'].map(name => colors[name]).reduce((best, hex) => worst(hex) > worst(best) ? hex : best, colors[wanted]);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* CSS for a theme's decoration. A focus ring is always drawn when the theme names one (at least 2px
|
|
73
|
+
* and 3:1 on the page's surfaces: the color is swapped for a visible one otherwise); motion only
|
|
74
|
+
* for people who have not asked for less of it.
|
|
75
|
+
*/
|
|
76
|
+
export function compileDecor(decor, targets, ctx) {
|
|
77
|
+
const out = [];
|
|
78
|
+
const { colors } = ctx;
|
|
79
|
+
const surfaces = [colors.bg, colors.surface, colors.page];
|
|
80
|
+
if (decor.dividers && targets.divider) {
|
|
81
|
+
const { style, color = 'border', width } = decor.dividers;
|
|
82
|
+
const line = style === 'none' ? '0 none' : `${style === 'hairline' ? 1 : width ?? (style === 'double' ? 3 : 1)}px ${style === 'hairline' ? 'solid' : style} ${colors[color]}`;
|
|
83
|
+
out.push(`:root:root :is(${targets.divider}){border-bottom:${line} !important}`);
|
|
84
|
+
}
|
|
85
|
+
if (decor.focusRing && targets.focusable) {
|
|
86
|
+
const { width = 2, style = 'solid', color = 'accent', offset = 2 } = decor.focusRing;
|
|
87
|
+
out.push(`:root:root :is(${targets.focusable}):focus-visible{outline:${Math.max(2, width)}px ${style} ${visibleOn(colors, color, surfaces, 3)} !important;outline-offset:${offset}px !important}`);
|
|
88
|
+
}
|
|
89
|
+
if (decor.selection) {
|
|
90
|
+
const fill = colors[decor.selection.fill];
|
|
91
|
+
const text = contrastRatio(colors[decor.selection.text], fill) >= 4.5 ? colors[decor.selection.text] : (contrastRatio('#ffffff', fill) >= contrastRatio('#000000', fill) ? '#ffffff' : '#000000');
|
|
92
|
+
// A bare ::selection: with an ancestor in front (`:root:root ::selection`) every node the site
|
|
93
|
+
// inserts costs the engine extra style recalculation (theme matrix: 4 elements per insertion, 2 without).
|
|
94
|
+
out.push(`::selection{background-color:${fill} !important;color:${text} !important}`);
|
|
95
|
+
}
|
|
96
|
+
if (decor.scrollbar) {
|
|
97
|
+
const { width, thumb = 'border', track, style } = decor.scrollbar;
|
|
98
|
+
const scroller = targets.scroller ?? 'html,body';
|
|
99
|
+
const thumbColor = visibleOn(colors, thumb, [track ? colors[track] : colors.page], 1.5);
|
|
100
|
+
out.push(`:root:root :is(${scroller}){scrollbar-color:${thumbColor} ${track ? colors[track] : 'transparent'} !important${width ? `;scrollbar-width:${width} !important` : ''}}`);
|
|
101
|
+
// The classic look needs the engine's own scrollbar parts; `scrollbar-color` would switch them off where both are set.
|
|
102
|
+
if (style === 'classic') {
|
|
103
|
+
const face = track ? colors[track] : colors.surface;
|
|
104
|
+
out.push(`@supports selector(::-webkit-scrollbar){:root:root :is(${scroller}){scrollbar-color:auto !important;scrollbar-width:auto !important}:root:root ::-webkit-scrollbar{width:16px;height:16px;background:${face}}:root:root ::-webkit-scrollbar-thumb{background:${colors.surface};box-shadow:inset -1px -1px ${colors.text},inset 1px 1px ${colors.bg},inset -2px -2px ${colors.muted},inset 2px 2px ${colors.elevated}}:root:root ::-webkit-scrollbar-corner{background:${face}}}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (decor.links && targets.link) {
|
|
108
|
+
const { underline } = decor.links;
|
|
109
|
+
out.push(`:root:root :is(${targets.link}){text-decoration:${underline === 'always' ? 'underline' : 'none'} !important;text-underline-offset:2px}`);
|
|
110
|
+
if (underline === 'hover')
|
|
111
|
+
out.push(`:root:root :is(${targets.link}):hover{text-decoration:underline !important}`);
|
|
112
|
+
}
|
|
113
|
+
if (decor.motion && (targets.moving || targets.pressable)) {
|
|
114
|
+
const { duration, curve = 'standard', press } = decor.motion;
|
|
115
|
+
const rules = [];
|
|
116
|
+
if (duration !== undefined && targets.moving) {
|
|
117
|
+
rules.push(`:root:root :is(${targets.moving}){transition:background-color ${duration}ms ${CURVES[curve]},color ${duration}ms ${CURVES[curve]},border-color ${duration}ms ${CURVES[curve]},box-shadow ${duration}ms ${CURVES[curve]},transform ${duration}ms ${CURVES[curve]} !important}`);
|
|
118
|
+
}
|
|
119
|
+
if (press !== undefined && press < 1 && targets.pressable)
|
|
120
|
+
rules.push(`:root:root :is(${targets.pressable}):active{transform:scale(${press}) !important}`);
|
|
121
|
+
if (rules.length)
|
|
122
|
+
out.push(`@media (prefers-reduced-motion:no-preference){${rules.join('')}}`);
|
|
123
|
+
}
|
|
124
|
+
if (decor.chrome) {
|
|
125
|
+
const css = targets.chrome?.[decor.chrome.kind]?.(decor.chrome.title ?? '', ctx);
|
|
126
|
+
if (css)
|
|
127
|
+
out.push(css);
|
|
128
|
+
}
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
/** A theme's text as a CSS string literal (for `content`): the allow-list of `chromeTitle` plus escaping of what could end the string. */
|
|
132
|
+
export const cssString = (value) => `"${value.replace(/[\\"\n\r\f]/g, match => `\\${match.charCodeAt(0).toString(16)} `)}"`;
|
|
133
|
+
//# sourceMappingURL=themeDecor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themeDecor.js","sourceRoot":"","sources":["../../../runtime/src/themeDecor.ts"],"names":[],"mappings":"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","sourcesContent":["// Decoration: what a theme draws between and around the components: divider lines, a title bar or a\n// masthead, the focus ring, selection, scrollbars, link underlines, the feel of motion. Fixed words\n// and clamped numbers, colors by role. Where the lines and bars go is the site's (its decor targets).\n// Pure.\n\nimport { contrastRatio } from './themeApi.ts';\nimport { COLOR_ROLES, type ColorRole, type RoleColors } from './themeComponents.ts';\n\nexport const DIVIDER_STYLES = ['none', 'hairline', 'solid', 'dashed', 'dotted', 'double'] as const;\nexport const CHROME_KINDS = ['none', 'titlebar', 'masthead', 'prompt'] as const;\nexport const RING_STYLES = ['solid', 'dashed', 'dotted', 'double'] as const;\nexport const MOTION_CURVES = ['standard', 'snappy', 'spring', 'linear', 'steps'] as const;\nexport const LINK_UNDERLINES = ['always', 'hover', 'never'] as const;\n\nexport type ThemeDecor = {\n dividers?: { style: typeof DIVIDER_STYLES[number]; color?: ColorRole; width?: number };\n /** A drawn frame around the main column: a window title bar, a newspaper masthead, a terminal prompt. `title` is plain text. */\n chrome?: { kind: typeof CHROME_KINDS[number]; title?: string };\n focusRing?: { width?: number; style?: typeof RING_STYLES[number]; color?: ColorRole; offset?: number };\n selection?: { fill: ColorRole; text: ColorRole };\n scrollbar?: { width?: 'auto' | 'thin'; thumb?: ColorRole; track?: ColorRole; style?: 'flat' | 'classic' };\n links?: { underline: typeof LINK_UNDERLINES[number] };\n motion?: { duration?: number; curve?: typeof MOTION_CURVES[number]; press?: number };\n};\n\nconst obj = (value: unknown): Record<string, unknown> => value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {};\nconst oneOf = <T extends string>(value: unknown, options: readonly T[]): T | undefined => options.includes(value as T) ? value as T : undefined;\nconst num = (value: unknown, min: number, max: number): number | undefined => typeof value === 'number' && Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : undefined;\nconst role = (value: unknown) => oneOf(value, COLOR_ROLES);\n/** Text a theme may put into a drawn bar: letters, digits, spaces and a little punctuation; it is written into a CSS string. */\nexport const chromeTitle = (value: unknown) => typeof value === 'string' ? value.replace(/[^\\p{L}\\p{N} .,:!?&+\\-_/#@*~()[\\]|>$]/gu, '').replace(/&/g, '+').trim().slice(0, 24) : '';\n\n/** The `decor` group from JSON. Null when nothing valid is left. */\nexport function sanitizeDecor(value: unknown): ThemeDecor | null {\n const source = obj(value);\n const out: ThemeDecor = {};\n const dividers = obj(source.dividers), dividerStyle = oneOf(dividers.style, DIVIDER_STYLES);\n if (dividerStyle) {\n const color = role(dividers.color), width = num(dividers.width, 0, 3);\n out.dividers = { style: dividerStyle, ...(color ? { color } : {}), ...(width !== undefined ? { width: +width.toFixed(1) } : {}) };\n }\n const chrome = obj(source.chrome), kind = oneOf(chrome.kind, CHROME_KINDS);\n if (kind && kind !== 'none') { const title = chromeTitle(chrome.title); out.chrome = { kind, ...(title ? { title } : {}) }; }\n const ring = obj(source.focusRing);\n if (Object.keys(ring).length) {\n const width = num(ring.width, 2, 4), style = oneOf(ring.style, RING_STYLES), color = role(ring.color), offset = num(ring.offset, 0, 4);\n const focusRing = { ...(width !== undefined ? { width: Math.round(width) } : {}), ...(style ? { style } : {}), ...(color ? { color } : {}), ...(offset !== undefined ? { offset: Math.round(offset) } : {}) };\n if (Object.keys(focusRing).length) out.focusRing = focusRing;\n }\n const selection = obj(source.selection), fill = role(selection.fill), text = role(selection.text);\n if (fill && text) out.selection = { fill, text };\n const bar = obj(source.scrollbar);\n if (Object.keys(bar).length) {\n const width = oneOf(bar.width, ['auto', 'thin'] as const), thumb = role(bar.thumb), track = role(bar.track), style = oneOf(bar.style, ['flat', 'classic'] as const);\n const scrollbar = { ...(width ? { width } : {}), ...(thumb ? { thumb } : {}), ...(track ? { track } : {}), ...(style ? { style } : {}) };\n if (Object.keys(scrollbar).length) out.scrollbar = scrollbar;\n }\n const underline = oneOf(obj(source.links).underline, LINK_UNDERLINES);\n if (underline) out.links = { underline };\n const motion = obj(source.motion);\n if (Object.keys(motion).length) {\n const duration = num(motion.duration, 0, 400), curve = oneOf(motion.curve, MOTION_CURVES), press = num(motion.press, 0.96, 1);\n const value = { ...(duration !== undefined ? { duration: Math.round(duration) } : {}), ...(curve ? { curve } : {}), ...(press !== undefined ? { press: +press.toFixed(3) } : {}) };\n if (Object.keys(value).length) out.motion = value;\n }\n return Object.keys(out).length ? out : null;\n}\n\n/** Where a site's decoration goes. Every entry is optional: a site without it draws nothing for that key. */\nexport type DecorTargets<Context> = {\n /** Rows whose bottom edge is the divider between items (a site's list cells). */\n divider?: string;\n /** Links inside running text. */\n link?: string;\n /** What takes keyboard focus. */\n focusable?: string;\n /** What moves with `motion` (buttons, links, rows). */\n moving?: string;\n /** What a press shrinks. */\n pressable?: string;\n /** The scrollable roots. */\n scroller?: string;\n /** The site's drawing of each chrome kind. */\n chrome?: Partial<Record<Exclude<typeof CHROME_KINDS[number], 'none'>, (title: string, ctx: Context) => string>>;\n};\n\nconst CURVES: Record<typeof MOTION_CURVES[number], string> = {\n standard: 'cubic-bezier(.2,.7,.2,1)', snappy: 'cubic-bezier(.3,1.4,.5,1)', spring: 'cubic-bezier(.2,1.6,.4,1)', linear: 'linear', steps: 'steps(3,end)',\n};\n\n/** The role among `candidates` that reaches `ratio` on every surface, else the most visible one. */\nfunction visibleOn(colors: RoleColors, wanted: ColorRole, surfaces: string[], ratio: number): string {\n const worst = (hex: string) => Math.min(...surfaces.map(surface => contrastRatio(hex, surface)));\n if (worst(colors[wanted]) >= ratio) return colors[wanted];\n return (['accent', 'text', 'inverse'] as ColorRole[]).map(name => colors[name]).reduce((best, hex) => worst(hex) > worst(best) ? hex : best, colors[wanted]);\n}\n\n/**\n * CSS for a theme's decoration. A focus ring is always drawn when the theme names one (at least 2px\n * and 3:1 on the page's surfaces: the color is swapped for a visible one otherwise); motion only\n * for people who have not asked for less of it.\n */\nexport function compileDecor<Context extends { colors: RoleColors }>(decor: ThemeDecor, targets: DecorTargets<Context>, ctx: Context): string[] {\n const out: string[] = [];\n const { colors } = ctx;\n const surfaces = [colors.bg, colors.surface, colors.page];\n if (decor.dividers && targets.divider) {\n const { style, color = 'border', width } = decor.dividers;\n const line = style === 'none' ? '0 none' : `${style === 'hairline' ? 1 : width ?? (style === 'double' ? 3 : 1)}px ${style === 'hairline' ? 'solid' : style} ${colors[color]}`;\n out.push(`:root:root :is(${targets.divider}){border-bottom:${line} !important}`);\n }\n if (decor.focusRing && targets.focusable) {\n const { width = 2, style = 'solid', color = 'accent', offset = 2 } = decor.focusRing;\n out.push(`:root:root :is(${targets.focusable}):focus-visible{outline:${Math.max(2, width)}px ${style} ${visibleOn(colors, color, surfaces, 3)} !important;outline-offset:${offset}px !important}`);\n }\n if (decor.selection) {\n const fill = colors[decor.selection.fill];\n const text = contrastRatio(colors[decor.selection.text], fill) >= 4.5 ? colors[decor.selection.text] : (contrastRatio('#ffffff', fill) >= contrastRatio('#000000', fill) ? '#ffffff' : '#000000');\n // A bare ::selection: with an ancestor in front (`:root:root ::selection`) every node the site\n // inserts costs the engine extra style recalculation (theme matrix: 4 elements per insertion, 2 without).\n out.push(`::selection{background-color:${fill} !important;color:${text} !important}`);\n }\n if (decor.scrollbar) {\n const { width, thumb = 'border', track, style } = decor.scrollbar;\n const scroller = targets.scroller ?? 'html,body';\n const thumbColor = visibleOn(colors, thumb, [track ? colors[track] : colors.page], 1.5);\n out.push(`:root:root :is(${scroller}){scrollbar-color:${thumbColor} ${track ? colors[track] : 'transparent'} !important${width ? `;scrollbar-width:${width} !important` : ''}}`);\n // The classic look needs the engine's own scrollbar parts; `scrollbar-color` would switch them off where both are set.\n if (style === 'classic') {\n const face = track ? colors[track] : colors.surface;\n out.push(`@supports selector(::-webkit-scrollbar){:root:root :is(${scroller}){scrollbar-color:auto !important;scrollbar-width:auto !important}:root:root ::-webkit-scrollbar{width:16px;height:16px;background:${face}}:root:root ::-webkit-scrollbar-thumb{background:${colors.surface};box-shadow:inset -1px -1px ${colors.text},inset 1px 1px ${colors.bg},inset -2px -2px ${colors.muted},inset 2px 2px ${colors.elevated}}:root:root ::-webkit-scrollbar-corner{background:${face}}}`);\n }\n }\n if (decor.links && targets.link) {\n const { underline } = decor.links;\n out.push(`:root:root :is(${targets.link}){text-decoration:${underline === 'always' ? 'underline' : 'none'} !important;text-underline-offset:2px}`);\n if (underline === 'hover') out.push(`:root:root :is(${targets.link}):hover{text-decoration:underline !important}`);\n }\n if (decor.motion && (targets.moving || targets.pressable)) {\n const { duration, curve = 'standard', press } = decor.motion;\n const rules: string[] = [];\n if (duration !== undefined && targets.moving) {\n rules.push(`:root:root :is(${targets.moving}){transition:background-color ${duration}ms ${CURVES[curve]},color ${duration}ms ${CURVES[curve]},border-color ${duration}ms ${CURVES[curve]},box-shadow ${duration}ms ${CURVES[curve]},transform ${duration}ms ${CURVES[curve]} !important}`);\n }\n if (press !== undefined && press < 1 && targets.pressable) rules.push(`:root:root :is(${targets.pressable}):active{transform:scale(${press}) !important}`);\n if (rules.length) out.push(`@media (prefers-reduced-motion:no-preference){${rules.join('')}}`);\n }\n if (decor.chrome) {\n const css = targets.chrome?.[decor.chrome.kind as Exclude<typeof CHROME_KINDS[number], 'none'>]?.(decor.chrome.title ?? '', ctx);\n if (css) out.push(css);\n }\n return out;\n}\n\n/** A theme's text as a CSS string literal (for `content`): the allow-list of `chromeTitle` plus escaping of what could end the string. */\nexport const cssString = (value: string) => `\"${value.replace(/[\\\\\"\\n\\r\\f]/g, match => `\\\\${match.charCodeAt(0).toString(16)} `)}\"`;\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export declare const SURFACE_NAMES: readonly ["canvas", "content", "card", "chrome", "raised", "panel", "strong", "accentFill", "tooltip"];
|
|
2
|
+
export type SurfaceName = typeof SURFACE_NAMES[number];
|
|
3
|
+
export type EdgeStyle = 'flat' | 'hairline' | 'outline' | 'bevel' | 'gloss';
|
|
4
|
+
export type DerivePalette = {
|
|
5
|
+
scheme?: 'light' | 'dark';
|
|
6
|
+
page?: string | null;
|
|
7
|
+
bg: string;
|
|
8
|
+
surface: string;
|
|
9
|
+
elevated: string;
|
|
10
|
+
face?: string | null;
|
|
11
|
+
border: string;
|
|
12
|
+
text: string;
|
|
13
|
+
muted: string;
|
|
14
|
+
accent: string;
|
|
15
|
+
inverse?: string | null;
|
|
16
|
+
inverse2?: string | null;
|
|
17
|
+
onInverse?: string | null;
|
|
18
|
+
hover?: string | null;
|
|
19
|
+
selected?: string | null;
|
|
20
|
+
};
|
|
21
|
+
export type DeriveInput = {
|
|
22
|
+
palette: DerivePalette;
|
|
23
|
+
edge?: {
|
|
24
|
+
style?: EdgeStyle;
|
|
25
|
+
strong?: boolean;
|
|
26
|
+
};
|
|
27
|
+
access?: 'standard' | 'high';
|
|
28
|
+
post?: {
|
|
29
|
+
style?: 'flat' | 'cards' | 'bubbles' | 'compact' | 'broadsheet';
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export type Surface = {
|
|
33
|
+
/** The fill (`fill2`: the far end of a gradient fill; inks read on both). */
|
|
34
|
+
fill: string;
|
|
35
|
+
fill2?: string;
|
|
36
|
+
ink: string;
|
|
37
|
+
inkSoft: string;
|
|
38
|
+
link: string;
|
|
39
|
+
line: string;
|
|
40
|
+
hover: string;
|
|
41
|
+
selected: string;
|
|
42
|
+
focus: string;
|
|
43
|
+
};
|
|
44
|
+
export type SurfaceSet = Record<SurfaceName, Surface> & {
|
|
45
|
+
scheme: 'light' | 'dark';
|
|
46
|
+
edge: EdgeStyle;
|
|
47
|
+
notes: string[];
|
|
48
|
+
};
|
|
49
|
+
/** The best ratio any ink can reach on every one of `fills` (black or white on the worst of them). */
|
|
50
|
+
export declare const reachable: (fills: string[]) => number;
|
|
51
|
+
/** Every surface of a theme. Notes list each ink the solver had to move. */
|
|
52
|
+
export declare function deriveSurfaces(input: DeriveInput): SurfaceSet;
|
|
53
|
+
/** The v2 palette and component hints as v3 derivation input (until the documents are v3, step 13). */
|
|
54
|
+
export declare function surfacesInputFromV2(colors: {
|
|
55
|
+
bg: string;
|
|
56
|
+
surface: string;
|
|
57
|
+
elevated: string;
|
|
58
|
+
border: string;
|
|
59
|
+
text: string;
|
|
60
|
+
muted: string;
|
|
61
|
+
accent: string;
|
|
62
|
+
page?: string | null;
|
|
63
|
+
inverse?: string | null;
|
|
64
|
+
onInverse?: string | null;
|
|
65
|
+
}, hints?: {
|
|
66
|
+
bevel?: boolean;
|
|
67
|
+
high?: boolean;
|
|
68
|
+
cards?: boolean;
|
|
69
|
+
}): DeriveInput;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Theme engine v3, step 5 (.omc/plans/theme-engine-v3.md 3.2): every surface the site and the shell
|
|
2
|
+
// paint, derived from a theme's tokens, with every ink solved for the fill it sits on (themeInk.ts).
|
|
3
|
+
// Pure. Consumers ask "what is the ink on the chrome", never "which palette role reads here".
|
|
4
|
+
//
|
|
5
|
+
// The input is the v3 palette shape; v2 documents reach it through `surfacesInputFromV2` until step 13
|
|
6
|
+
// makes v3 the stored format.
|
|
7
|
+
import { contrastRatio, relativeLuminance } from "./themeApi.js";
|
|
8
|
+
import { inkOn, inkOnEvery, mixOklab, TARGET } from "./themeInk.js";
|
|
9
|
+
export const SURFACE_NAMES = ['canvas', 'content', 'card', 'chrome', 'raised', 'panel', 'strong', 'accentFill', 'tooltip'];
|
|
10
|
+
const isDarkFill = (hex) => relativeLuminance(hex) < 0.18;
|
|
11
|
+
/** The best ratio any ink can reach on every one of `fills` (black or white on the worst of them). */
|
|
12
|
+
export const reachable = (fills) => Math.max(...['#000000', '#ffffff'].map(pole => Math.min(...fills.map(fill => contrastRatio(pole, fill)))));
|
|
13
|
+
/**
|
|
14
|
+
* One surface. Inks are solved on the fill (both ends of a gradient); the hover and selected states are
|
|
15
|
+
* then pulled back toward the fill until every ink still reads on them, so a hovered or selected row
|
|
16
|
+
* never costs contrast. A target no ink can reach on this fill (7:1 on a mid tone) is capped at the
|
|
17
|
+
* best there is and noted.
|
|
18
|
+
*/
|
|
19
|
+
function surface(name, fill, p, input, notes, opts = {}) {
|
|
20
|
+
const fills = opts.fill2 ? [fill, opts.fill2] : [fill];
|
|
21
|
+
const best = reachable(fills);
|
|
22
|
+
const cap = (target, what) => {
|
|
23
|
+
if (best >= target)
|
|
24
|
+
return target;
|
|
25
|
+
notes.push(`${name}.${what}: ${target}:1 is out of reach on ${fills.join('/')}, ${best.toFixed(2)}:1 at most`);
|
|
26
|
+
return best;
|
|
27
|
+
};
|
|
28
|
+
const textTarget = cap(input.access === 'high' ? TARGET.high : TARGET.text, 'ink');
|
|
29
|
+
const softTarget = cap(TARGET.text, 'inkSoft');
|
|
30
|
+
const solve = (preferred, target, what) => {
|
|
31
|
+
const result = inkOnEvery(fills, preferred, target);
|
|
32
|
+
if (result.adjusted)
|
|
33
|
+
notes.push(`${name}.${what} ${preferred} -> ${result.ink} (${result.ratio.toFixed(2)}:1)`);
|
|
34
|
+
return result.ink;
|
|
35
|
+
};
|
|
36
|
+
const ink = solve(opts.inkPreferred ?? p.text, textTarget, 'ink');
|
|
37
|
+
const inkSoft = solve(p.muted, softTarget, 'inkSoft');
|
|
38
|
+
const link = solve(p.accent, softTarget, 'link');
|
|
39
|
+
const reads = (state) => contrastRatio(ink, state) >= textTarget - 1e-9 && contrastRatio(inkSoft, state) >= softTarget - 1e-9 && contrastRatio(link, state) >= softTarget - 1e-9;
|
|
40
|
+
/** A state `t` of the way from the fill to `toward`, shrunk until the inks read on it. */
|
|
41
|
+
const state = (toward, t, what) => {
|
|
42
|
+
for (let k = t; k > 0.004; k /= 2) {
|
|
43
|
+
const candidate = mixOklab(fill, toward, k);
|
|
44
|
+
if (reads(candidate)) {
|
|
45
|
+
if (k !== t)
|
|
46
|
+
notes.push(`${name}.${what} step ${t} -> ${k.toFixed(3)}`);
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return fill;
|
|
51
|
+
};
|
|
52
|
+
const dark = isDarkFill(fill);
|
|
53
|
+
// States: the theme's own hover/selected when they keep every ink readable, else a neutral step toward the ink (never the accent hue for hover).
|
|
54
|
+
const hover = opts.hover && reads(opts.hover) ? opts.hover : state(ink, dark ? 0.08 : 0.05, 'hover');
|
|
55
|
+
const selected = opts.selected && reads(opts.selected) ? opts.selected : state(p.accent, 0.14, 'selected');
|
|
56
|
+
const strongLine = input.edge?.strong || input.access === 'high';
|
|
57
|
+
const lineTarget = Math.min(best, strongLine || input.edge?.style === 'outline' ? TARGET.nonText : 1.3);
|
|
58
|
+
return {
|
|
59
|
+
fill, ...(opts.fill2 ? { fill2: opts.fill2 } : {}),
|
|
60
|
+
ink, inkSoft, link,
|
|
61
|
+
line: strongLine ? ink : inkOnEvery(fills, p.border, lineTarget).ink,
|
|
62
|
+
hover, selected, focus: inkOnEvery(fills, p.accent, Math.min(best, TARGET.nonText)).ink,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** Every surface of a theme. Notes list each ink the solver had to move. */
|
|
66
|
+
export function deriveSurfaces(input) {
|
|
67
|
+
const p = input.palette;
|
|
68
|
+
const notes = [];
|
|
69
|
+
const scheme = p.scheme ?? (relativeLuminance(p.bg) < relativeLuminance(p.text) ? 'dark' : 'light');
|
|
70
|
+
const edge = input.edge?.style ?? 'hairline';
|
|
71
|
+
const face = p.face ?? (edge === 'bevel' ? mixOklab(p.surface, p.border, 0.2) : p.surface);
|
|
72
|
+
const cards = input.post?.style === 'cards' || input.post?.style === 'bubbles';
|
|
73
|
+
// The strong fill (title bars, inverted buttons): its gradient end moves until one ink reads on both ends.
|
|
74
|
+
const inverse = p.inverse ?? p.text;
|
|
75
|
+
let inverse2 = p.inverse2 ?? inverse;
|
|
76
|
+
const strongPreferred = p.onInverse ?? p.bg;
|
|
77
|
+
if (inverse2 !== inverse) {
|
|
78
|
+
const both = inkOnEvery([inverse, inverse2], strongPreferred, TARGET.text);
|
|
79
|
+
if (both.ratio < TARGET.text) {
|
|
80
|
+
const ink = inkOn(inverse, strongPreferred, TARGET.text).ink;
|
|
81
|
+
const moved = inkOn(ink, inverse2, TARGET.text).ink;
|
|
82
|
+
notes.push(`strong.fill2 ${inverse2} -> ${moved} (one ink on both ends)`);
|
|
83
|
+
inverse2 = moved;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// The accent fill's label: white or the page colour, whichever reads better, then solved.
|
|
87
|
+
const accentLabel = contrastRatio('#ffffff', p.accent) >= contrastRatio(p.bg, p.accent) ? '#ffffff' : p.bg;
|
|
88
|
+
const tooltipFill = mixOklab(p.text, p.bg, 0.12);
|
|
89
|
+
const set = {
|
|
90
|
+
canvas: surface('canvas', p.page ?? p.bg, p, input, notes),
|
|
91
|
+
content: surface('content', p.bg, p, input, notes, { hover: p.hover, selected: p.selected }),
|
|
92
|
+
card: surface('card', cards ? p.surface : p.bg, p, input, notes, { hover: p.hover, selected: p.selected }),
|
|
93
|
+
chrome: surface('chrome', face, p, input, notes, { hover: p.hover, selected: p.selected }),
|
|
94
|
+
raised: surface('raised', p.elevated, p, input, notes),
|
|
95
|
+
panel: surface('panel', p.bg, p, input, notes, { hover: p.hover, selected: p.selected }),
|
|
96
|
+
strong: surface('strong', inverse, p, input, notes, { ...(inverse2 !== inverse ? { fill2: inverse2 } : {}), inkPreferred: strongPreferred }),
|
|
97
|
+
accentFill: surface('accentFill', p.accent, p, input, notes, { inkPreferred: accentLabel }),
|
|
98
|
+
tooltip: surface('tooltip', tooltipFill, p, input, notes, { inkPreferred: p.bg }),
|
|
99
|
+
};
|
|
100
|
+
return { ...set, scheme, edge, notes };
|
|
101
|
+
}
|
|
102
|
+
/** The v2 palette and component hints as v3 derivation input (until the documents are v3, step 13). */
|
|
103
|
+
export function surfacesInputFromV2(colors, hints = {}) {
|
|
104
|
+
return {
|
|
105
|
+
palette: {
|
|
106
|
+
page: colors.page ?? null, bg: colors.bg, surface: colors.surface, elevated: colors.elevated, border: colors.border,
|
|
107
|
+
text: colors.text, muted: colors.muted, accent: colors.accent, inverse: colors.inverse ?? null, onInverse: colors.onInverse ?? null,
|
|
108
|
+
// A bevelled v2 theme draws its chrome from `page` (Windows 98: the silver face) and its title bar from inverse to accent.
|
|
109
|
+
face: hints.bevel ? colors.page ?? colors.elevated : null,
|
|
110
|
+
inverse2: hints.bevel ? colors.accent : null,
|
|
111
|
+
},
|
|
112
|
+
edge: { style: hints.bevel ? 'bevel' : 'hairline' },
|
|
113
|
+
access: hints.high ? 'high' : 'standard',
|
|
114
|
+
post: { style: hints.cards ? 'cards' : 'flat' },
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=themeDerive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themeDerive.js","sourceRoot":"","sources":["../../../runtime/src/themeDerive.ts"],"names":[],"mappings":"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","sourcesContent":["// Theme engine v3, step 5 (.omc/plans/theme-engine-v3.md 3.2): every surface the site and the shell\n// paint, derived from a theme's tokens, with every ink solved for the fill it sits on (themeInk.ts).\n// Pure. Consumers ask \"what is the ink on the chrome\", never \"which palette role reads here\".\n//\n// The input is the v3 palette shape; v2 documents reach it through `surfacesInputFromV2` until step 13\n// makes v3 the stored format.\n\nimport { contrastRatio, relativeLuminance } from './themeApi.ts';\nimport { inkOn, inkOnEvery, mixOklab, TARGET } from './themeInk.ts';\n\nexport const SURFACE_NAMES = ['canvas', 'content', 'card', 'chrome', 'raised', 'panel', 'strong', 'accentFill', 'tooltip'] as const;\nexport type SurfaceName = typeof SURFACE_NAMES[number];\nexport type EdgeStyle = 'flat' | 'hairline' | 'outline' | 'bevel' | 'gloss';\n\nexport type DerivePalette = {\n scheme?: 'light' | 'dark';\n page?: string | null; bg: string; surface: string; elevated: string; face?: string | null;\n border: string; text: string; muted: string; accent: string;\n inverse?: string | null; inverse2?: string | null; onInverse?: string | null;\n hover?: string | null; selected?: string | null;\n};\nexport type DeriveInput = {\n palette: DerivePalette;\n edge?: { style?: EdgeStyle; strong?: boolean };\n access?: 'standard' | 'high';\n post?: { style?: 'flat' | 'cards' | 'bubbles' | 'compact' | 'broadsheet' };\n};\n\nexport type Surface = {\n /** The fill (`fill2`: the far end of a gradient fill; inks read on both). */\n fill: string; fill2?: string;\n ink: string; inkSoft: string; link: string; line: string;\n hover: string; selected: string; focus: string;\n};\nexport type SurfaceSet = Record<SurfaceName, Surface> & { scheme: 'light' | 'dark'; edge: EdgeStyle; notes: string[] };\n\nconst isDarkFill = (hex: string) => relativeLuminance(hex) < 0.18;\n\n/** The best ratio any ink can reach on every one of `fills` (black or white on the worst of them). */\nexport const reachable = (fills: string[]) => Math.max(...['#000000', '#ffffff'].map(pole => Math.min(...fills.map(fill => contrastRatio(pole, fill)))));\n\n/**\n * One surface. Inks are solved on the fill (both ends of a gradient); the hover and selected states are\n * then pulled back toward the fill until every ink still reads on them, so a hovered or selected row\n * never costs contrast. A target no ink can reach on this fill (7:1 on a mid tone) is capped at the\n * best there is and noted.\n */\nfunction surface(name: SurfaceName, fill: string, p: DerivePalette, input: DeriveInput, notes: string[], opts: { fill2?: string; inkPreferred?: string; hover?: string | null; selected?: string | null } = {}): Surface {\n const fills = opts.fill2 ? [fill, opts.fill2] : [fill];\n const best = reachable(fills);\n const cap = (target: number, what: string) => {\n if (best >= target) return target;\n notes.push(`${name}.${what}: ${target}:1 is out of reach on ${fills.join('/')}, ${best.toFixed(2)}:1 at most`);\n return best;\n };\n const textTarget = cap(input.access === 'high' ? TARGET.high : TARGET.text, 'ink');\n const softTarget = cap(TARGET.text, 'inkSoft');\n const solve = (preferred: string, target: number, what: string) => {\n const result = inkOnEvery(fills, preferred, target);\n if (result.adjusted) notes.push(`${name}.${what} ${preferred} -> ${result.ink} (${result.ratio.toFixed(2)}:1)`);\n return result.ink;\n };\n const ink = solve(opts.inkPreferred ?? p.text, textTarget, 'ink');\n const inkSoft = solve(p.muted, softTarget, 'inkSoft');\n const link = solve(p.accent, softTarget, 'link');\n const reads = (state: string) => contrastRatio(ink, state) >= textTarget - 1e-9 && contrastRatio(inkSoft, state) >= softTarget - 1e-9 && contrastRatio(link, state) >= softTarget - 1e-9;\n /** A state `t` of the way from the fill to `toward`, shrunk until the inks read on it. */\n const state = (toward: string, t: number, what: string) => {\n for (let k = t; k > 0.004; k /= 2) { const candidate = mixOklab(fill, toward, k); if (reads(candidate)) { if (k !== t) notes.push(`${name}.${what} step ${t} -> ${k.toFixed(3)}`); return candidate; } }\n return fill;\n };\n const dark = isDarkFill(fill);\n // States: the theme's own hover/selected when they keep every ink readable, else a neutral step toward the ink (never the accent hue for hover).\n const hover = opts.hover && reads(opts.hover) ? opts.hover : state(ink, dark ? 0.08 : 0.05, 'hover');\n const selected = opts.selected && reads(opts.selected) ? opts.selected : state(p.accent, 0.14, 'selected');\n const strongLine = input.edge?.strong || input.access === 'high';\n const lineTarget = Math.min(best, strongLine || input.edge?.style === 'outline' ? TARGET.nonText : 1.3);\n return {\n fill, ...(opts.fill2 ? { fill2: opts.fill2 } : {}),\n ink, inkSoft, link,\n line: strongLine ? ink : inkOnEvery(fills, p.border, lineTarget).ink,\n hover, selected, focus: inkOnEvery(fills, p.accent, Math.min(best, TARGET.nonText)).ink,\n };\n}\n\n/** Every surface of a theme. Notes list each ink the solver had to move. */\nexport function deriveSurfaces(input: DeriveInput): SurfaceSet {\n const p = input.palette;\n const notes: string[] = [];\n const scheme = p.scheme ?? (relativeLuminance(p.bg) < relativeLuminance(p.text) ? 'dark' : 'light');\n const edge = input.edge?.style ?? 'hairline';\n const face = p.face ?? (edge === 'bevel' ? mixOklab(p.surface, p.border, 0.2) : p.surface);\n const cards = input.post?.style === 'cards' || input.post?.style === 'bubbles';\n // The strong fill (title bars, inverted buttons): its gradient end moves until one ink reads on both ends.\n const inverse = p.inverse ?? p.text;\n let inverse2 = p.inverse2 ?? inverse;\n const strongPreferred = p.onInverse ?? p.bg;\n if (inverse2 !== inverse) {\n const both = inkOnEvery([inverse, inverse2], strongPreferred, TARGET.text);\n if (both.ratio < TARGET.text) {\n const ink = inkOn(inverse, strongPreferred, TARGET.text).ink;\n const moved = inkOn(ink, inverse2, TARGET.text).ink;\n notes.push(`strong.fill2 ${inverse2} -> ${moved} (one ink on both ends)`);\n inverse2 = moved;\n }\n }\n // The accent fill's label: white or the page colour, whichever reads better, then solved.\n const accentLabel = contrastRatio('#ffffff', p.accent) >= contrastRatio(p.bg, p.accent) ? '#ffffff' : p.bg;\n const tooltipFill = mixOklab(p.text, p.bg, 0.12);\n const set = {\n canvas: surface('canvas', p.page ?? p.bg, p, input, notes),\n content: surface('content', p.bg, p, input, notes, { hover: p.hover, selected: p.selected }),\n card: surface('card', cards ? p.surface : p.bg, p, input, notes, { hover: p.hover, selected: p.selected }),\n chrome: surface('chrome', face, p, input, notes, { hover: p.hover, selected: p.selected }),\n raised: surface('raised', p.elevated, p, input, notes),\n panel: surface('panel', p.bg, p, input, notes, { hover: p.hover, selected: p.selected }),\n strong: surface('strong', inverse, p, input, notes, { ...(inverse2 !== inverse ? { fill2: inverse2 } : {}), inkPreferred: strongPreferred }),\n accentFill: surface('accentFill', p.accent, p, input, notes, { inkPreferred: accentLabel }),\n tooltip: surface('tooltip', tooltipFill, p, input, notes, { inkPreferred: p.bg }),\n } satisfies Record<SurfaceName, Surface>;\n return { ...set, scheme, edge, notes };\n}\n\n/** The v2 palette and component hints as v3 derivation input (until the documents are v3, step 13). */\nexport function surfacesInputFromV2(colors: { bg: string; surface: string; elevated: string; border: string; text: string; muted: string; accent: string; page?: string | null; inverse?: string | null; onInverse?: string | null }, hints: { bevel?: boolean; high?: boolean; cards?: boolean } = {}): DeriveInput {\n return {\n palette: {\n page: colors.page ?? null, bg: colors.bg, surface: colors.surface, elevated: colors.elevated, border: colors.border,\n text: colors.text, muted: colors.muted, accent: colors.accent, inverse: colors.inverse ?? null, onInverse: colors.onInverse ?? null,\n // A bevelled v2 theme draws its chrome from `page` (Windows 98: the silver face) and its title bar from inverse to accent.\n face: hints.bevel ? colors.page ?? colors.elevated : null,\n inverse2: hints.bevel ? colors.accent : null,\n },\n edge: { style: hints.bevel ? 'bevel' : 'hairline' },\n access: hints.high ? 'high' : 'standard',\n post: { style: hints.cards ? 'cards' : 'flat' },\n };\n}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type ThemeSpec } from './themeSpec.ts';
|
|
2
|
+
export type DoctorAdvice = {
|
|
3
|
+
/** `lighter`: a lighter mechanism would do; `performance`, `accessibility`, `contrast`: a cost. */
|
|
4
|
+
kind: 'lighter' | 'performance' | 'accessibility' | 'contrast';
|
|
5
|
+
/** Stable id of the finding, for tests (`css-radius`, `contrast-text`). */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Its words in the catalog: `wb.doctor.<key>.found` and `wb.doctor.<key>.fix` (`css-radius`, `contrast`). */
|
|
8
|
+
key: string;
|
|
9
|
+
/** A token path of the theme (`colors.text`, `components.postText.fontSize`) or the CSS rule (`.card { border-radius }`). */
|
|
10
|
+
where: string;
|
|
11
|
+
/** Values for the `{name}` slots of the words. */
|
|
12
|
+
params: Record<string, string>;
|
|
13
|
+
/** English: what was found. */
|
|
14
|
+
text: string;
|
|
15
|
+
/** English: how to fix it. */
|
|
16
|
+
fix: string;
|
|
17
|
+
};
|
|
18
|
+
/** The doctor's words in English (the source of `wb.doctor.*` in the catalogs). */
|
|
19
|
+
export declare const DOCTOR_MESSAGES: {
|
|
20
|
+
readonly 'wb.doctor.css-radius.found': "This rule sets corner radii in CSS.";
|
|
21
|
+
readonly 'wb.doctor.css-radius.fix': "Set them with the radius of a part under components, or shape.radius for all of them: no CSS needed, and it keeps working when the site renames its classes.";
|
|
22
|
+
readonly 'wb.doctor.css-bevel.found': "This rule draws a bevelled edge with stacked inset shadows.";
|
|
23
|
+
readonly 'wb.doctor.css-bevel.fix': "Use borderStyle \"bevel-out\" or \"bevel-in\" on a part under components: it draws the bevel from the theme’s colors.";
|
|
24
|
+
readonly 'wb.doctor.css-hide.found': "This rule hides something with display: none.";
|
|
25
|
+
readonly 'wb.doctor.css-hide.fix': "Use visible on a part under components (avatars, counts, names) or a layout variant such as sidebar: hidden; the owner can then switch it back.";
|
|
26
|
+
readonly 'wb.doctor.css-color.found': "This rule uses a literal color.";
|
|
27
|
+
readonly 'wb.doctor.css-color.fix': "Name a role (text, muted, accent, surface…) in colors or in a component, so the contrast pass covers it.";
|
|
28
|
+
readonly 'wb.doctor.css-font.found': "This rule sets a font family.";
|
|
29
|
+
readonly 'wb.doctor.css-font.fix': "Use font.roles: it sets the post, heading, numbers and mono faces without CSS.";
|
|
30
|
+
readonly 'wb.doctor.css-has.found': "This rule uses :has(), which is matched again on every change of the page.";
|
|
31
|
+
readonly 'wb.doctor.css-has.fix': "Keep :has() off rules that repeat down a timeline, or anchor the rule on a part.";
|
|
32
|
+
readonly 'wb.doctor.css-universal.found': "This rule uses a universal selector (*), matched against every element.";
|
|
33
|
+
readonly 'wb.doctor.css-universal.fix': "Anchor the rule on a part instead.";
|
|
34
|
+
readonly 'wb.doctor.css-blur.found': "This rule blurs what is behind it (backdrop-filter), which is costly on parts that repeat.";
|
|
35
|
+
readonly 'wb.doctor.css-blur.fix': "Use the glass fill of bars and panels: it is the cheaper place for blur.";
|
|
36
|
+
readonly 'wb.doctor.css-outline-none.found': "This rule removes the focus outline, so keyboard focus is no longer visible.";
|
|
37
|
+
readonly 'wb.doctor.css-outline-none.fix': "Use decor.focusRing to draw a visible focus ring instead.";
|
|
38
|
+
readonly 'wb.doctor.css-motion.found': "This rule animates without checking for reduced motion.";
|
|
39
|
+
readonly 'wb.doctor.css-motion.fix': "Keep motion inside @media (prefers-reduced-motion: no-preference), or let decor.motion do it for you.";
|
|
40
|
+
readonly 'wb.doctor.css-size.found': "The CSS is more than 20,000 characters long.";
|
|
41
|
+
readonly 'wb.doctor.css-size.fix': "The site recalculates styles with every rule; tokens and component settings compile to fewer rules.";
|
|
42
|
+
readonly 'wb.doctor.contrast.found': "The {token} color was adjusted to stay readable ({ratio}:1 on the background).";
|
|
43
|
+
readonly 'wb.doctor.contrast.fix': "Pick a lighter or darker {token} color; until then the theme is shown with the adjusted one.";
|
|
44
|
+
readonly 'wb.doctor.glass-post.found': "Glass is set on posts, but it is not drawn: blur on every post of a timeline is too costly.";
|
|
45
|
+
readonly 'wb.doctor.glass-post.fix': "Use a solid or tinted fill for posts and keep glass for bars and panels.";
|
|
46
|
+
readonly 'wb.doctor.small-post-text.found': "Post text is {size}px, which is hard to read for many people.";
|
|
47
|
+
readonly 'wb.doctor.small-post-text.fix': "Use 14px or more for the post text size, or raise the text size of the whole theme.";
|
|
48
|
+
readonly 'wb.doctor.nav-moved.found': "The navigation is moved to the {position}, which changes where people look for it.";
|
|
49
|
+
readonly 'wb.doctor.nav-moved.fix': "It only applies on wide panes, and the owner can turn layout changes off. Keep the default position unless the layout needs it.";
|
|
50
|
+
};
|
|
51
|
+
/** Advice for a theme document: every finding, with where it is. Empty when there is nothing to say. */
|
|
52
|
+
export declare function themeDoctor(theme: ThemeSpec): DoctorAdvice[];
|