From 1ef0653f3b5f2c3e6ad974cf0ed362065657465a Mon Sep 17 00:00:00 2001 From: Grace Kind Date: Tue, 28 Jul 2026 16:35:00 -0500 Subject: [PATCH] Move plugins to sidebar --- package.json | 2 +- src/css/style.css | 7 +- src/img/icons/custom/widgets-line.svg | 1 + src/img/icons/custom/widgets-solid.svg | 1 + src/js/app.js | 23 +++-- src/js/navigation.js | 4 + .../templates/icons/widgetsIcon.template.js | 62 ++++++++++++ src/js/templates/sidebar.template.js | 7 ++ ...ugins.view.js => installedPlugins.view.js} | 71 ++++++++------ ...nDetail.view.js => pluginSettings.view.js} | 12 +-- src/js/views/settings.view.js | 8 -- .../specs/concerns/sidebarNavigation.test.js | 11 +++ .../specs/flows/installRemotePlugin.test.js | 4 +- .../flows/installUnregisteredPlugin.test.js | 4 +- ....test.js => installedPlugins.view.test.js} | 98 +++++++++++++++---- ...ew.test.js => pluginSettings.view.test.js} | 32 +++--- tests/e2e/specs/views/settings.view.test.js | 7 +- tests/unit/specs/navigation.test.js | 17 ++++ .../specs/templates/sidebar.template.test.js | 12 +++ 19 files changed, 284 insertions(+), 99 deletions(-) create mode 100644 src/img/icons/custom/widgets-line.svg create mode 100644 src/img/icons/custom/widgets-solid.svg create mode 100644 src/js/templates/icons/widgetsIcon.template.js rename src/js/views/{settings/plugins.view.js => installedPlugins.view.js} (86%) rename src/js/views/{settings/pluginDetail.view.js => pluginSettings.view.js} (92%) rename tests/e2e/specs/views/{settings/plugins.view.test.js => installedPlugins.view.test.js} (72%) rename tests/e2e/specs/views/{settings/pluginDetail.view.test.js => pluginSettings.view.test.js} (89%) diff --git a/package.json b/package.json index 6d0d8c67..49ea981d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "impro", - "version": "0.18.106", + "version": "0.18.107", "type": "module", "scripts": { "start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve", diff --git a/src/css/style.css b/src/css/style.css index b6a7408f..9d2981d1 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -9978,7 +9978,7 @@ image-cropper { } #community-plugins-view .error-state, -#settings-plugins-view .error-state { +#installed-plugins-view .error-state { padding: 32px 20px; } @@ -10021,6 +10021,11 @@ image-cropper { margin-top: 4px; } +a.plugin-list-item-info { + color: inherit; + text-decoration: none; +} + .plugin-list-item-controls { display: flex; align-items: center; diff --git a/src/img/icons/custom/widgets-line.svg b/src/img/icons/custom/widgets-line.svg new file mode 100644 index 00000000..cab68efa --- /dev/null +++ b/src/img/icons/custom/widgets-line.svg @@ -0,0 +1 @@ + diff --git a/src/img/icons/custom/widgets-solid.svg b/src/img/icons/custom/widgets-solid.svg new file mode 100644 index 00000000..66108327 --- /dev/null +++ b/src/img/icons/custom/widgets-solid.svg @@ -0,0 +1 @@ + diff --git a/src/js/app.js b/src/js/app.js index e713a7ae..3062b90e 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -24,8 +24,8 @@ import settingsMutedWordsView from "/js/views/settings/mutedWords.view.js"; import settingsBlockedAccountsView from "/js/views/settings/blockedAccounts.view.js"; import settingsMutedAccountsView from "/js/views/settings/mutedAccounts.view.js"; import settingsAdvancedView from "/js/views/settings/advanced.view.js"; -import settingsPluginsView from "/js/views/settings/plugins.view.js"; -import settingsPluginDetailView from "/js/views/settings/pluginDetail.view.js"; +import installedPluginsView from "/js/views/installedPlugins.view.js"; +import pluginSettingsView from "/js/views/pluginSettings.view.js"; import communityPluginsView from "/js/views/communityPlugins.view.js"; import communityPluginListingView from "/js/views/communityPluginListing.view.js"; import feedDetailView from "/js/views/feedDetail.view.js"; @@ -322,15 +322,18 @@ export async function main() { () => settingsAdvancedView, settingsRouteOptions, ); + const pluginsRouteOptions = { + layoutOptions: { activeNavItem: "plugins" }, + }; router.addRoute( - "/settings/plugins", - () => settingsPluginsView, - settingsRouteOptions, + "/plugins/installed", + () => installedPluginsView, + pluginsRouteOptions, ); router.addRoute( - "/settings/plugins/:pluginId", - () => settingsPluginDetailView, - settingsRouteOptions, + "/plugin/:pluginId/settings", + () => pluginSettingsView, + pluginsRouteOptions, ); router.addRoute("/plugins/community", () => communityPluginsView); router.addRoute( @@ -342,6 +345,10 @@ export async function main() { "/settings/plugins/community": () => "/plugins/community", "/settings/plugins/community/:pluginId": (params) => `/plugins/community/${encodeURIComponent(params.pluginId)}`, + // Old installed plugin URLs + "/settings/plugins": () => "/plugins/installed", + "/settings/plugins/:pluginId": (params) => + `/plugin/${encodeURIComponent(params.pluginId)}/settings`, }); router.setNotFoundView(() => notFoundView); diff --git a/src/js/navigation.js b/src/js/navigation.js index 53b86667..c8316b6f 100644 --- a/src/js/navigation.js +++ b/src/js/navigation.js @@ -97,6 +97,10 @@ export function linkToGroupChatDetails(convoId) { return `/messages/${encodePathSegment(convoId)}/settings`; } +export function linkToPluginSettings(pluginId) { + return `/plugin/${encodePathSegment(pluginId)}/settings`; +} + export function linkToCommunityPlugin(pluginId) { return `/plugins/community/${encodePathSegment(pluginId)}`; } diff --git a/src/js/templates/icons/widgetsIcon.template.js b/src/js/templates/icons/widgetsIcon.template.js new file mode 100644 index 00000000..91fb081c --- /dev/null +++ b/src/js/templates/icons/widgetsIcon.template.js @@ -0,0 +1,62 @@ +import { html } from "/js/lib/lit-html.js"; +import { classnames } from "/js/utils.js"; + +// Source: src/img/icons/custom/widgets-line.svg, src/img/icons/custom/widgets-solid.svg +export function widgetsIconTemplate({ filled = false } = {}) { + return html`
+ ${filled + ? html` + + + + + + + ` + : html` + + + + + + + `} +
`; +} diff --git a/src/js/templates/sidebar.template.js b/src/js/templates/sidebar.template.js index 57aede3c..b7eee19f 100644 --- a/src/js/templates/sidebar.template.js +++ b/src/js/templates/sidebar.template.js @@ -11,6 +11,7 @@ import { userIconTemplate } from "/js/templates/icons/userIcon.template.js"; import { searchIconTemplate } from "/js/templates/icons/searchIcon.template.js"; import { chatIconTemplate } from "/js/templates/icons/chatIcon.template.js"; import { settingsIconTemplate } from "/js/templates/icons/settingsIcon.template.js"; +import { widgetsIconTemplate } from "/js/templates/icons/widgetsIcon.template.js"; import { notificationsIconTemplate } from "/js/templates/icons/notificationsIcon.template.js"; import { hashtagIconTemplate } from "/js/templates/icons/hashtagIcon.template.js"; import { bookmarkIconTemplate } from "/js/templates/icons/bookmarkIcon.template.js"; @@ -219,6 +220,12 @@ export function sidebarTemplate({ url: currentUser ? `/profile/${currentUser.did}` : "", disabled: !currentUser, }, + { + id: "plugins", + icon: widgetsIconTemplate, + label: "Plugins", + url: "/plugins/installed", + }, { id: "settings", icon: settingsIconTemplate, diff --git a/src/js/views/settings/plugins.view.js b/src/js/views/installedPlugins.view.js similarity index 86% rename from src/js/views/settings/plugins.view.js rename to src/js/views/installedPlugins.view.js index dc10f6ab..7ede9cb6 100644 --- a/src/js/views/settings/plugins.view.js +++ b/src/js/views/installedPlugins.view.js @@ -12,13 +12,14 @@ import { confirmModal } from "/js/modals/confirm.modal.js"; import { showToast } from "/js/toasts.js"; import { Signal, SignalSet, ReactiveStore } from "/js/signals.js"; import { PermissionsDeclinedError } from "/js/plugins/pluginService.js"; +import { linkToPluginSettings, linkToCommunityPlugin } from "/js/navigation.js"; import "/js/components/toggle-switch.js"; -class SettingsPluginsView extends View { +class InstalledPluginsView extends View { async render({ root, router, layout, context: { pluginService } }) { await auth.requireAuth(); - const state = new ReactiveStore("settingsPluginsView"); + const state = new ReactiveStore("installedPluginsView"); state.$uninstallingIds = new SignalSet(); state.$enablingIds = new SignalSet(); state.$disablingIds = new SignalSet(); @@ -148,7 +149,9 @@ class SettingsPluginsView extends View { bindToPage(root, layout, "active-nav-click", (event) => { event.preventDefault(); - router.go("/settings"); + if (window.scrollY > 0) { + window.scrollTo({ top: -1, behavior: "smooth" }); + } }); bindPageTitle(root, () => "Plugins"); @@ -162,10 +165,9 @@ class SettingsPluginsView extends View { const hasAvailableUpdates = availableUpdates !== null && availableUpdates.size > 0; render( - html`
+ html`
${headerTemplate({ title: "Plugins", - backButtonFallbackRoute: "/settings", })}
@@ -241,6 +243,28 @@ class SettingsPluginsView extends View { state.$enablingIds.has(plugin.id) || state.$disablingIds.has(plugin.id) || isUpdating; + const isLocal = plugin.id.endsWith("__LOCAL"); + const infoContent = html` +
+ ${plugin.name} + ${isLocal + ? html`local` + : ""} +
+ ${plugin.description + ? html`
+ ${plugin.description} +
` + : ""} +
+ Version: ${plugin.version} +
+
+ By ${plugin.author} +
+ `; // Keyed to avoid flipping animation when plugins are added / removed return keyed( plugin.id, @@ -253,29 +277,16 @@ class SettingsPluginsView extends View { : ""}" ?inert=${isPending} > -
-
- ${plugin.name} - ${plugin.id.endsWith("__LOCAL") - ? html`local` - : ""} -
- ${plugin.description - ? html`
- ${plugin.description} -
` - : ""} -
- Version: ${plugin.version} -
-
- By ${plugin.author} -
-
+ ${isLocal + ? html`
+ ${infoContent} +
` + : html`
+ ${infoContent} + `}
${hasUpdate ? html`