UX: Move links in Sidebar footer under community section (#17774)

Now that we have a "more..." links drawer, we can move some of the links
in footer into the links drawer. The footer itself does not have much
horizontal or vertical space for us to work with and hence limits the
amount of links which we can add to it.
This commit is contained in:
Alan Guo Xiang Tan 2022-08-03 14:47:03 +08:00 committed by GitHub
parent 53dd9b0c66
commit d1d760ae7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 252 additions and 99 deletions

View File

@ -8,6 +8,9 @@ import TrackedSectionLink from "discourse/lib/sidebar/community-section/tracked-
import MyPostsSectionLink from "discourse/lib/sidebar/community-section/my-posts-section-link";
import GroupsSectionLink from "discourse/lib/sidebar/community-section/groups-section-link";
import UsersSectionLink from "discourse/lib/sidebar/community-section/users-section-link";
import AboutSectionLink from "discourse/lib/sidebar/community-section/about-section-link";
import FAQSectionLink from "discourse/lib/sidebar/community-section/faq-section-link";
import AdminSectionLink from "discourse/lib/sidebar/community-section/admin-section-link";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
@ -19,7 +22,14 @@ const MAIN_SECTION_LINKS = [
MyPostsSectionLink,
];
const MORE_SECTION_LINKS = [GroupsSectionLink, UsersSectionLink];
const ADMIN_MAIN_SECTION_LINKS = [AdminSectionLink];
const MORE_SECTION_LINKS = [
GroupsSectionLink,
UsersSectionLink,
AboutSectionLink,
FAQSectionLink,
];
export default class SidebarCommunitySection extends GlimmerComponent {
@service router;
@ -31,11 +41,16 @@ export default class SidebarCommunitySection extends GlimmerComponent {
currentUser: this.currentUser,
appEvents: this.appEvents,
router: this.router,
siteSettings: this.siteSettings,
});
}
);
sectionLinks = MAIN_SECTION_LINKS.map((sectionLinkClass) => {
#mainSectionLinks = this.currentUser.staff
? [...MAIN_SECTION_LINKS, ...ADMIN_MAIN_SECTION_LINKS]
: [...MAIN_SECTION_LINKS];
sectionLinks = this.#mainSectionLinks.map((sectionLinkClass) => {
return new sectionLinkClass({
topicTrackingState: this.topicTrackingState,
currentUser: this.currentUser,

View File

@ -8,6 +8,22 @@ export default class SectionLink extends GlimmerComponent {
}
}
get classNames() {
return `${this.args.class} sidebar-section-link sidebar-section-link-${this.args.linkName}`;
}
get models() {
if (this.args.model) {
return [this.args.model];
}
if (this.args.models) {
return this.args.models;
}
return [];
}
get prefixCSS() {
const color = this.args.prefixColor;

View File

@ -0,0 +1,21 @@
import I18n from "I18n";
import BaseSectionLink from "discourse/lib/sidebar/community-section/base-section-link";
export default class AboutSectionLink extends BaseSectionLink {
get name() {
return "about";
}
get route() {
return "about";
}
get title() {
return I18n.t("about.simple_title");
}
get text() {
return I18n.t("about.simple_title");
}
}

View File

@ -0,0 +1,21 @@
import I18n from "I18n";
import BaseSectionLink from "discourse/lib/sidebar/community-section/base-section-link";
export default class AdminSectionLink extends BaseSectionLink {
get name() {
return "admin";
}
get route() {
return "admin";
}
get title() {
return I18n.t("admin_title");
}
get text() {
return I18n.t("admin_title");
}
}

View File

@ -2,11 +2,18 @@
* Base class representing a sidebar topics section link interface.
*/
export default class BaseSectionLink {
constructor({ topicTrackingState, currentUser, appEvents, router } = {}) {
constructor({
topicTrackingState,
currentUser,
appEvents,
router,
siteSettings,
} = {}) {
this.router = router;
this.topicTrackingState = topicTrackingState;
this.currentUser = currentUser;
this.appEvents = appEvents;
this.siteSettings = siteSettings;
}
/**
@ -28,6 +35,11 @@ export default class BaseSectionLink {
this._notImplemented();
}
/**
* @returns {string} href attribute for the link. This property will take precedence over the `route` property when set.
*/
get href() {}
/**
* @returns {Object} Model for <LinkTo> component. See https://api.emberjs.com/ember/release/classes/Ember.Templates.components/methods/LinkTo?anchor=LinkTo
*/

View File

@ -0,0 +1,25 @@
import I18n from "I18n";
import BaseSectionLink from "discourse/lib/sidebar/community-section/base-section-link";
export default class FAQSectionLink extends BaseSectionLink {
get name() {
return "faq";
}
get route() {
return "faq";
}
get href() {
return this.siteSettings.faq_url;
}
get title() {
return I18n.t("faq");
}
get text() {
return I18n.t("faq");
}
}

View File

@ -11,6 +11,7 @@
{{#each this.sectionLinks as |sectionLink|}}
<Sidebar::SectionLink
@linkName={{sectionLink.name}}
@href={{sectionLink.href}}
@route={{sectionLink.route}}
@query={{sectionLink.query}}
@title={{sectionLink.title}}

View File

@ -1,17 +1,5 @@
<div class="sidebar-footer-wrapper">
<div class="sidebar-footer-container">
<div class="sidebar-footer-links">
<LinkTo @route="about" title={{i18n "about.simple_title"}} class="sidebar-footer-link sidebar-footer-link-about">
{{i18n "about.simple_title"}}
</LinkTo>
{{#if this.currentUser.staff}}
<LinkTo @route="admin" title={{i18n "admin_title"}} class="sidebar-footer-link sidebar-footer-link-admin">
{{i18n "admin_title"}}
</LinkTo>
{{/if}}
</div>
<div class="sidebar-footer-actions">
<DButton
@action={{route-action "showKeyboardShortcutsHelp"}}

View File

@ -25,6 +25,7 @@
<Sidebar::SectionLink
@linkName={{sectionLink.name}}
@route={{sectionLink.route}}
@href={{sectionLink.href}}
@query={{sectionLink.query}}
@title={{sectionLink.title}}
@content={{sectionLink.text}}

View File

@ -1,63 +1,71 @@
<div class="sidebar-section-link-wrapper">
<Sidebar::SectionLinkTo
@class={{concat @class (concat " sidebar-section-link sidebar-section-link-" @linkName)}}
@route={{@route}}
@query={{@query}}
@models={{if @model (array @model) (if @models @models (array))}}
@current-when={{@currentWhen}}
@title={{@title}}
>
{{#if @prefixValue }}
<span class="sidebar-section-link-prefix {{@prefixType}} {{@prefixCSSClass}}" style={{this.prefixCSS}}>
{{#if (eq @prefixType "image")}}
<img src={{@prefixValue}} class="prefix-image">
{{/if}}
{{#if @href}}
<a href={{@href}} rel="noopener noreferrer" target="_blank" class={{this.classNames}} title={{@title}}>
<span class="sidebar-section-link-content-text">
{{@content}}
</span>
</a>
{{else}}
<Sidebar::SectionLinkTo
@class={{this.classNames}}
@route={{@route}}
@query={{@query}}
@models={{this.models}}
@current-when={{@currentWhen}}
@title={{@title}}
>
{{#if @prefixValue }}
<span class="sidebar-section-link-prefix {{@prefixType}} {{@prefixCSSClass}}" style={{this.prefixCSS}}>
{{#if (eq @prefixType "image")}}
<img src={{@prefixValue}} class="prefix-image">
{{/if}}
{{#if (eq @prefixType "text")}}
{{@prefixValue}}
{{/if}}
{{#if (eq @prefixType "text")}}
{{@prefixValue}}
{{/if}}
{{#if (eq @prefixType "icon")}}
{{d-icon @prefixValue class="prefix-icon"}}
{{/if}}
{{#if (eq @prefixType "icon")}}
{{d-icon @prefixValue class="prefix-icon"}}
{{/if}}
{{#if @prefixBadge}}
{{d-icon @prefixBadge class="prefix-badge"}}
{{/if}}
{{#if @prefixBadge}}
{{d-icon @prefixBadge class="prefix-badge"}}
{{/if}}
</span>
{{/if}}
<span class="sidebar-section-link-content-text">
{{@content}}
</span>
{{#if @badgeText}}
<span class="sidebar-section-link-content-badge">
{{@badgeText}}
</span>
{{/if}}
{{#if @suffixValue}}
<span class="sidebar-section-link-suffix {{@suffixType}} {{@suffixCSSClass}}">
{{#if (eq @suffixType "icon")}}
{{d-icon @suffixValue}}
{{/if}}
</span>
{{/if}}
</Sidebar::SectionLinkTo>
{{#if @hoverValue}}
<span class="sidebar-section-link-hover">
<button
type="button"
title={{@hoverTitle}}
class="sidebar-section-hover-button"
{{on "click" @hoverAction}}
>
{{#if (eq @hoverType "icon")}}
{{d-icon @hoverValue class="hover-icon"}}
{{/if}}
</button>
</span>
{{/if}}
<span class="sidebar-section-link-content-text">
{{@content}}
</span>
{{#if @badgeText}}
<span class="sidebar-section-link-content-badge">
{{@badgeText}}
</span>
{{/if}}
{{#if @suffixValue}}
<span class="sidebar-section-link-suffix {{@suffixType}} {{@suffixCSSClass}}">
{{#if (eq @suffixType "icon")}}
{{d-icon @suffixValue}}
{{/if}}
</span>
{{/if}}
</Sidebar::SectionLinkTo>
{{#if @hoverValue}}
<span class="sidebar-section-link-hover">
<button
type="button"
title={{@hoverTitle}}
class="sidebar-section-hover-button"
{{on "click" @hoverAction}}
>
{{#if (eq @hoverType "icon")}}
{{d-icon @hoverValue class="hover-icon"}}
{{/if}}
</button>
</span>
{{/if}}
</div>

View File

@ -1,6 +1,11 @@
import I18n from "I18n";
import { test } from "qunit";
import { click, currentURL, visit } from "@ember/test-helpers";
import {
click,
currentRouteName,
currentURL,
visit,
} from "@ember/test-helpers";
import {
acceptance,
count,
@ -8,6 +13,7 @@ import {
loggedInUser,
publishToMessageBus,
query,
updateCurrentUser,
} from "discourse/tests/helpers/qunit-helpers";
import topicFixtures from "discourse/tests/fixtures/discovery-fixtures";
import { cloneJSON } from "discourse-common/lib/object";
@ -293,6 +299,71 @@ acceptance("Sidebar - Community Section", function (needs) {
);
});
test("navigating to about from sidebar", async function (assert) {
await visit("/");
await click(
".sidebar-section-community .sidebar-more-section-links-details-summary"
);
await click(".sidebar-section-community .sidebar-section-link-about");
assert.strictEqual(
currentURL(),
"/about",
"navigates to about route correctly"
);
});
test("navigating to FAQ from sidebar", async function (assert) {
await visit("/");
await click(
".sidebar-section-community .sidebar-more-section-links-details-summary"
);
await click(".sidebar-section-community .sidebar-section-link-faq");
assert.strictEqual(
currentURL(),
"/faq",
"navigates to faq route correctly"
);
});
test("navigating to custom FAQ URL from sidebar", async function (assert) {
this.siteSettings.faq_url = "http://some.faq.url";
await visit("/");
await click(
".sidebar-section-community .sidebar-more-section-links-details-summary"
);
assert.strictEqual(
query(".sidebar-section-community .sidebar-section-link-faq").href,
"http://some.faq.url/",
"href attribute is set to custom FAQ URL on the section link"
);
});
test("navigating to admin from sidebar", async function (assert) {
await visit("/");
await click(".sidebar-section-community .sidebar-section-link-admin");
assert.strictEqual(currentRouteName(), "admin.dashboard.general");
});
test("admin section link is not shown to non-staff users", async function (assert) {
updateCurrentUser({ admin: false, moderator: false });
await visit("/");
assert.notOk(
exists(".sidebar-section-community .sidebar-section-link-admin")
);
});
test("clicking on my posts link", async function (assert) {
await visit("/t/280");
await click(".sidebar-section-community .sidebar-section-link-my-posts");

View File

@ -1,12 +1,8 @@
import I18n from "I18n";
import { test } from "qunit";
import { click, currentRouteName, visit } from "@ember/test-helpers";
import {
acceptance,
exists,
updateCurrentUser,
} from "discourse/tests/helpers/qunit-helpers";
import { click, visit } from "@ember/test-helpers";
import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers";
acceptance("Sidebar - Anon User", function () {
// Don't show sidebar for anon user until we know what we want to display
@ -98,13 +94,6 @@ acceptance(
enable_sidebar: true,
});
test("navigating to about route using sidebar", async function (assert) {
await visit("/");
await click(".sidebar-footer-link-about");
assert.strictEqual(currentRouteName(), "about");
});
test("viewing keyboard shortcuts using sidebar", async function (assert) {
await visit("/");
await click(
@ -119,21 +108,6 @@ acceptance(
);
});
test("navigating to admin route using sidebar", async function (assert) {
await visit("/");
await click(".sidebar-footer-link-admin");
assert.strictEqual(currentRouteName(), "admin.dashboard.general");
});
test("admin link is not shown in sidebar for non-admin user", async function (assert) {
updateCurrentUser({ admin: false, moderator: false });
await visit("/");
assert.notOk(exists(".sidebar-footer-link-admin"));
});
test("sidebar is disabled on wizard route", async function (assert) {
await visit("/wizard");