diff --git a/app/assets/javascripts/discourse/app/components/sidebar/community-section.js b/app/assets/javascripts/discourse/app/components/sidebar/community-section.js
index c6cc1f59d67..dd4668febcc 100644
--- a/app/assets/javascripts/discourse/app/components/sidebar/community-section.js
+++ b/app/assets/javascripts/discourse/app/components/sidebar/community-section.js
@@ -12,18 +12,26 @@ import UsersSectionLink from "discourse/lib/sidebar/community-section/users-sect
import { action } from "@ember/object";
import { next } from "@ember/runloop";
-const DEFAULT_SECTION_LINKS = [
+const MAIN_SECTION_LINKS = [
EverythingSectionLink,
TrackedSectionLink,
- GroupsSectionLink,
- UsersSectionLink,
MyPostsSectionLink,
];
-export default class SidebarCommunitySection extends GlimmerComponent {
- configuredSectionLinks = [...DEFAULT_SECTION_LINKS, ...customSectionLinks];
+const MORE_SECTION_LINKS = [GroupsSectionLink, UsersSectionLink];
- sectionLinks = this.configuredSectionLinks.map((sectionLinkClass) => {
+export default class SidebarCommunitySection extends GlimmerComponent {
+ moreSectionLinks = [...MORE_SECTION_LINKS, ...customSectionLinks].map(
+ (sectionLinkClass) => {
+ return new sectionLinkClass({
+ topicTrackingState: this.topicTrackingState,
+ currentUser: this.currentUser,
+ appEvents: this.appEvents,
+ });
+ }
+ );
+
+ sectionLinks = MAIN_SECTION_LINKS.map((sectionLinkClass) => {
return new sectionLinkClass({
topicTrackingState: this.topicTrackingState,
currentUser: this.currentUser,
diff --git a/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.js b/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.js
new file mode 100644
index 00000000000..a38ccdd4be0
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/components/sidebar/more-section-links.js
@@ -0,0 +1,92 @@
+import { tracked } from "@glimmer/tracking";
+import { action } from "@ember/object";
+import { inject as service } from "@ember/service";
+import { bind } from "discourse-common/utils/decorators";
+import GlimmerComponent from "discourse/components/glimmer";
+
+export default class SidebarMoreSectionLinks extends GlimmerComponent {
+ @tracked shouldDisplaySectionLinks = false;
+ @tracked activeSectionLink;
+ @service router;
+
+ constructor() {
+ super(...arguments);
+ this.#setActiveSectionLink();
+ this.router.on("routeDidChange", this, this.#setActiveSectionLink);
+ }
+
+ willDestroy() {
+ this.#removeClickEventListener();
+ this.router.off("routeDidChange", this, this.#setActiveSectionLink);
+ }
+
+ get sectionLinks() {
+ if (this.activeSectionLink) {
+ return this.args.sectionLinks.filter((sectionLink) => {
+ return sectionLink.name !== this.activeSectionLink.name;
+ });
+ } else {
+ return this.args.sectionLinks;
+ }
+ }
+
+ @bind
+ closeDetails(event) {
+ if (this.shouldDisplaySectionLinks) {
+ const isLinkClick = event.target.className.includes(
+ "sidebar-section-link"
+ );
+
+ if (isLinkClick || this.#isOutsideDetailsClick(event)) {
+ document
+ .querySelector(".sidebar-more-section-links-details")
+ ?.removeAttribute("open");
+
+ this.toggleSectionLinks();
+ }
+ }
+ }
+
+ @action
+ registerClickListener() {
+ this.#addClickEventListener();
+ }
+
+ @action
+ unregisterClickListener() {
+ this.#removeClickEventListener();
+ }
+
+ @action
+ toggleSectionLinks() {
+ this.shouldDisplaySectionLinks = !this.shouldDisplaySectionLinks;
+ }
+
+ #removeClickEventListener() {
+ document.removeEventListener("click", this.closeDetails);
+ }
+
+ #addClickEventListener() {
+ document.addEventListener("click", this.closeDetails);
+ }
+
+ #isOutsideDetailsClick(event) {
+ return !event.composedPath().some((element) => {
+ return element.className === "sidebar-more-section-links-details";
+ });
+ }
+
+ #setActiveSectionLink() {
+ const activeSectionLink = this.args.sectionLinks.find((sectionLink) => {
+ const args = [sectionLink.route];
+
+ if (sectionLink.model) {
+ args.push(sectionLink.model);
+ }
+
+ return this.router.isActive(...args) && sectionLink;
+ });
+
+ this.activeSectionLink = activeSectionLink;
+ }
+}
diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs
index 5a17d28bd21..93dcb3a8bc2 100644
--- a/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/sidebar/community-section.hbs
@@ -19,4 +19,6 @@
@badgeText={{sectionLink.badgeText}}
@model={{sectionLink.model}} />
{{/each}}
+
+
diff --git a/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs b/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs
new file mode 100644
index 00000000000..d3f978f997d
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/templates/components/sidebar/more-section-links.hbs
@@ -0,0 +1,36 @@
+{{#if this.activeSectionLink}}
+
+{{/if}}
+
+
diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-community-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-community-section-test.js
index 1b95741c5cb..390f73c97bf 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-community-section-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-community-section-test.js
@@ -114,6 +114,45 @@ acceptance("Sidebar - Community Section", function (needs) {
);
});
+ test("clicking on more... link", async function (assert) {
+ await visit("/");
+
+ await click(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ );
+
+ assert.ok(
+ exists(
+ ".sidebar-section-community .sidebar-more-section-links-details-content"
+ ),
+ "additional section links are displayed"
+ );
+
+ await click(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ );
+
+ assert.notOk(
+ exists(
+ ".sidebar-section-community .sidebar-more-section-links-details-content"
+ ),
+ "additional section links are hidden"
+ );
+
+ await click(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ );
+
+ await click("#main-outlet");
+
+ assert.notOk(
+ exists(
+ ".sidebar-section-community .sidebar-more-section-links-details-content"
+ ),
+ "additional section links are hidden when clicking outside"
+ );
+ });
+
test("clicking on everything link", async function (assert) {
await visit("/t/280");
await click(".sidebar-section-community .sidebar-section-link-everything");
@@ -162,6 +201,16 @@ acceptance("Sidebar - Community Section", function (needs) {
test("clicking on users link", async function (assert) {
await visit("/t/280");
+
+ assert.notOk(
+ exists(".sidebar-section-community .sidebar-section-link-users"),
+ "users link is not displayed in sidebar when it is not the active route"
+ );
+
+ await click(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ );
+
await click(".sidebar-section-community .sidebar-section-link-users");
assert.strictEqual(
@@ -180,10 +229,35 @@ acceptance("Sidebar - Community Section", function (needs) {
exists(".sidebar-section-community .sidebar-section-link-users.active"),
"the users link is marked as active"
);
+
+ assert.strictEqual(
+ query(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ ).textContent.trim(),
+ I18n.t("sidebar.more_count", { count: 1 }),
+ "displays the right count as users link is currently active"
+ );
+
+ await visit("/u");
+
+ assert.ok(
+ exists(".sidebar-section-community .sidebar-section-link-users.active"),
+ "users link is displayed in sidebar when it is the active route"
+ );
});
test("clicking on groups link", async function (assert) {
await visit("/t/280");
+
+ assert.notOk(
+ exists(".sidebar-section-community .sidebar-section-link-groups"),
+ "groups link is not displayed in sidebar when it is not the active route"
+ );
+
+ await click(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ );
+
await click(".sidebar-section-community .sidebar-section-link-groups");
assert.strictEqual(
@@ -202,6 +276,21 @@ acceptance("Sidebar - Community Section", function (needs) {
exists(".sidebar-section-community .sidebar-section-link-groups.active"),
"the groups link is marked as active"
);
+
+ assert.strictEqual(
+ query(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ ).textContent.trim(),
+ I18n.t("sidebar.more_count", { count: 1 }),
+ "displays the right count as groups link is currently active"
+ );
+
+ await visit("/g");
+
+ assert.ok(
+ exists(".sidebar-section-community .sidebar-section-link-groups.active"),
+ "groups link is displayed in sidebar when it is the active route"
+ );
});
test("clicking on my posts link", async function (assert) {
@@ -679,6 +768,10 @@ acceptance("Sidebar - Community Section", function (needs) {
await visit("/");
+ await click(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ );
+
assert.strictEqual(
query(".sidebar-section-link-unread").textContent.trim(),
"unread topics",
@@ -724,6 +817,11 @@ acceptance("Sidebar - Community Section", function (needs) {
});
await visit("/");
+
+ await click(
+ ".sidebar-section-community .sidebar-more-section-links-details-summary"
+ );
+
await click(".sidebar-section-link-user-summary");
assert.strictEqual(
diff --git a/app/assets/stylesheets/common/base/_index.scss b/app/assets/stylesheets/common/base/_index.scss
index ca3f8b20991..6f6103e87a2 100644
--- a/app/assets/stylesheets/common/base/_index.scss
+++ b/app/assets/stylesheets/common/base/_index.scss
@@ -47,6 +47,7 @@
@import "sidebar";
@import "sidebar-footer";
@import "sidebar-section";
+@import "sidebar-more-section-links";
@import "sidebar-section-link";
@import "tagging";
@import "tooltip";
diff --git a/app/assets/stylesheets/common/base/sidebar-more-section-links.scss b/app/assets/stylesheets/common/base/sidebar-more-section-links.scss
new file mode 100644
index 00000000000..92c36017e3c
--- /dev/null
+++ b/app/assets/stylesheets/common/base/sidebar-more-section-links.scss
@@ -0,0 +1,32 @@
+.sidebar-more-section-links-details {
+ margin-left: 1.5em;
+
+ .sidebar-more-section-links-details-summary {
+ padding: 0.35em 0.5em;
+ color: var(--tertiary);
+ font-size: var(--font-down-1);
+ transition: background-color 0.25s;
+
+ &:hover {
+ background: var(--d-sidebar-highlight-color);
+ }
+
+ list-style: none;
+
+ &::before {
+ display: none;
+ }
+ }
+
+ .sidebar-more-section-links-details-content {
+ position: absolute;
+ background-color: var(--secondary);
+ width: 100%;
+ box-shadow: shadow("dropdown");
+ z-index: z("base") + 1;
+
+ .sidebar-section-link-wrapper {
+ margin-left: none;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/common/base/sidebar-section-link.scss b/app/assets/stylesheets/common/base/sidebar-section-link.scss
index 7abae61ed5f..2f6251c33ee 100644
--- a/app/assets/stylesheets/common/base/sidebar-section-link.scss
+++ b/app/assets/stylesheets/common/base/sidebar-section-link.scss
@@ -134,6 +134,8 @@
}
}
-#main-outlet-wrapper .sidebar-section-link-wrapper {
+#main-outlet-wrapper
+ .sidebar-section-link-wrapper:not(.sidebar-more-section-links-details-content
+ .sidebar-section-link-wrapper) {
margin-left: 1.5em;
}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index e299b4bcf4a..17dcbfd8991 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -4077,6 +4077,7 @@ en:
one: "%{count} new"
other: "%{count} new"
toggle_section: "toggle section"
+ more_count: "%{count} more..."
sections:
messages:
header_link_title: "personal messages"