diff --git a/app/assets/javascripts/discourse/app/components/sidebar.hbs b/app/assets/javascripts/discourse/app/components/sidebar.hbs
index 2ccf92362e6..a00d6704470 100644
--- a/app/assets/javascripts/discourse/app/components/sidebar.hbs
+++ b/app/assets/javascripts/discourse/app/components/sidebar.hbs
@@ -1,4 +1,12 @@
+ {{#if this.showSwitchPanelButtonsOnTop}}
+
+ {{/if}}
+
{{#if this.showMainPanel}}
{{/if}}
- {{#each this.switchPanelButtons as |button|}}
-
- {{/each}}
+ {{/unless}}
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/sidebar.js b/app/assets/javascripts/discourse/app/components/sidebar.js
index 5fa3d37c529..5518721c16b 100644
--- a/app/assets/javascripts/discourse/app/components/sidebar.js
+++ b/app/assets/javascripts/discourse/app/components/sidebar.js
@@ -2,17 +2,17 @@ import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { bind } from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
+import { action } from "@ember/object";
import {
currentPanelKey,
customPanels as sidebarCustomPanels,
} from "discourse/lib/sidebar/custom-sections";
-import { action } from "@ember/object";
export default class Sidebar extends Component {
@service appEvents;
@service site;
+ @service siteSettings;
@service currentUser;
- @service router;
@tracked currentPanelKey = currentPanelKey;
constructor() {
@@ -33,6 +33,10 @@ export default class Sidebar extends Component {
);
}
+ get showSwitchPanelButtonsOnTop() {
+ return this.siteSettings.default_sidebar_switch_panel_position === "top";
+ }
+
get switchPanelButtons() {
if (sidebarCustomPanels.length === 1 || !this.currentUser) {
return [];
@@ -69,14 +73,7 @@ export default class Sidebar extends Component {
}
@action
- switchPanel(panel) {
- this.currentPanel.lastKnownURL = this.router.currentURL;
- this.currentPanelKey = panel.key;
- const url = panel.lastKnownURL || panel.switchButtonDefaultUrl;
- if (url === "/") {
- this.router.transitionTo("latest");
- } else {
- this.router.transitionTo(url);
- }
+ setCurrentPanelKey(key) {
+ this.currentPanelKey = key;
}
}
diff --git a/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.hbs b/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.hbs
new file mode 100644
index 00000000000..aee2505a104
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.hbs
@@ -0,0 +1,8 @@
+{{#each @buttons as |button|}}
+
+{{/each}}
\ No newline at end of file
diff --git a/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.js b/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.js
new file mode 100644
index 00000000000..f5f49cb35db
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/sidebar/switch-panel-buttons.js
@@ -0,0 +1,19 @@
+import Component from "@glimmer/component";
+import { inject as service } from "@ember/service";
+import { action } from "@ember/object";
+
+export default class SwitchPanelButtons extends Component {
+ @service router;
+
+ @action
+ switchPanel(currentPanel, panel) {
+ currentPanel.lastKnownURL = this.router.currentURL;
+ this.args.setCurrentPanelKey(panel.key);
+ const url = panel.lastKnownURL || panel.switchButtonDefaultUrl;
+ if (url === "/") {
+ this.router.transitionTo("discovery.latest");
+ } else {
+ this.router.transitionTo(url);
+ }
+ }
+}
diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/custom-sections.js b/app/assets/javascripts/discourse/app/lib/sidebar/custom-sections.js
index e162dc30aeb..c2f2d579242 100644
--- a/app/assets/javascripts/discourse/app/lib/sidebar/custom-sections.js
+++ b/app/assets/javascripts/discourse/app/lib/sidebar/custom-sections.js
@@ -19,7 +19,7 @@ class MainSidebarPanel {
}
get switchButtonDefaultUrl() {
- return "/latest";
+ return "/";
}
}
diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js
index c8443369ef1..c19e1731b52 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js
@@ -1025,5 +1025,23 @@ acceptance("Sidebar - Plugin API", function (needs) {
assert
.dom(".sidebar-section[data-section-name='test-chat-channels']")
.doesNotExist();
+ assert.dom(".sidebar-sections + button").exists();
+
+ assert
+ .dom("#d-sidebar .sidebar-sections + .sidebar__panel-switch-button")
+ .exists();
+ assert
+ .dom("#d-sidebar .sidebar__panel-switch-button + .sidebar-sections")
+ .doesNotExist();
+
+ this.siteSettings.default_sidebar_switch_panel_position = "top";
+ await visit("/");
+
+ assert
+ .dom("#d-sidebar .sidebar-sections + .sidebar__panel-switch-button")
+ .doesNotExist();
+ assert
+ .dom("#d-sidebar .sidebar__panel-switch-button + .sidebar-sections")
+ .exists();
});
});
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index b0fb18e7c7b..70428a480ac 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -2357,6 +2357,7 @@ en:
enable_offline_indicator: "Display a message to users when it is detected that they have no network connection"
default_sidebar_link_to_filtered_list: "Make navigation menu links link to filtered list by default."
default_sidebar_show_count_of_new_items: "Make navigation menu links show count of new items instead of badges by default."
+ default_sidebar_switch_panel_position: "Position of sidebar switch panel buttons"
retain_web_hook_events_period_days: "Number of days to retain web hook event records."
retry_web_hook_events: "Automatically retry failed web hook events for 4 times. Time gaps between the retries are 1, 5, 25 and 125 minutes."
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 2a9fcf9e022..51b3a72f2cd 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -2160,6 +2160,13 @@ navigation:
type: tag_list
default: ""
client: true
+ default_sidebar_switch_panel_position:
+ default: "bottom"
+ type: enum
+ client: true
+ choices:
+ - "top"
+ - "bottom"
embedding:
embed_by_username: