UX: Reduce number of links displayed in Community by default (#17703)

Additional links are hidden by default and can be accessed via the
"more..." link.
This commit is contained in:
Alan Guo Xiang Tan 2022-07-28 16:46:46 +08:00 committed by GitHub
parent 988a175e94
commit 9efeaf2ae3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 279 additions and 7 deletions

View File

@ -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,

View File

@ -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;
}
}

View File

@ -19,4 +19,6 @@
@badgeText={{sectionLink.badgeText}}
@model={{sectionLink.model}} />
{{/each}}
<Sidebar::MoreSectionLinks @sectionLinks={{this.moreSectionLinks}} />
</Sidebar::Section>

View File

@ -0,0 +1,36 @@
{{#if this.activeSectionLink}}
<Sidebar::SectionLink
@linkName={{this.activeSectionLink.name}}
@route={{this.activeSectionLink.route}}
@query={{this.activeSectionLink.query}}
@title={{this.activeSectionLink.title}}
@content={{this.activeSectionLink.text}}
@currentWhen={{this.activeSectionLink.currentWhen}}
@badgeText={{this.activeSectionLink.badgeText}}
@model={{this.activeSectionLink.model}} />
{{/if}}
<details class="sidebar-more-section-links-details" {{on "click" this.toggleSectionLinks}}>
<summary class="sidebar-more-section-links-details-summary" >
{{i18n "sidebar.more_count" (hash count=this.sectionLinks.length)}}
</summary>
{{#if this.shouldDisplaySectionLinks}}
<div class="sidebar-more-section-links-details-content"
{{did-insert this.registerClickListener}}
{{will-destroy this.unregisterClickListener}} >
{{#each this.sectionLinks as |sectionLink|}}
<Sidebar::SectionLink
@linkName={{sectionLink.name}}
@route={{sectionLink.route}}
@query={{sectionLink.query}}
@title={{sectionLink.title}}
@content={{sectionLink.text}}
@currentWhen={{sectionLink.currentWhen}}
@badgeText={{sectionLink.badgeText}}
@model={{sectionLink.model}} />
{{/each}}
</div>
{{/if}}
</details>

View File

@ -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(

View File

@ -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";

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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"