UX: replaces custom more menu by d-menu (#29090)

One of the big advantages is a nicer menu on mobile.

This commit also fixes a bug where the close modal action was called for any destroyed d-menu trigger, even if this specific menu was not expanding, which means it was closing a different modal than its own modal, given we can only have one modal at a time.
This commit is contained in:
Joffrey JAFFEUX
2025-01-20 12:00:11 +01:00
committed by GitHub
parent 2c81e24bca
commit 89ff7d51e6
25 changed files with 206 additions and 205 deletions

View File

@ -158,6 +158,12 @@ export default class DModal extends Component {
this.closeModal(CLOSE_INITIATED_BY_SWIPE_DOWN); this.closeModal(CLOSE_INITIATED_BY_SWIPE_DOWN);
} }
@action
handleWrapperPointerDown(e) {
// prevents hamburger menu to close on modal backdrop click
e.stopPropagation();
}
@action @action
handleWrapperClick(e) { handleWrapperClick(e) {
if (e.button !== 0) { if (e.button !== 0) {
@ -396,6 +402,8 @@ export default class DModal extends Component {
enabled=this.dismissable enabled=this.dismissable
}} }}
{{on "click" this.handleWrapperClick}} {{on "click" this.handleWrapperClick}}
{{! template-lint-disable no-pointer-down-event-binding }}
{{on "pointerdown" this.handleWrapperPointerDown}}
></div> ></div>
{{/unless}} {{/unless}}
</ConditionalInElement> </ConditionalInElement>

View File

@ -12,7 +12,7 @@ import closeOnClickOutside from "../../modifiers/close-on-click-outside";
import SidebarHamburgerDropdown from "../sidebar/hamburger-dropdown"; import SidebarHamburgerDropdown from "../sidebar/hamburger-dropdown";
const CLOSE_ON_CLICK_SELECTORS = const CLOSE_ON_CLICK_SELECTORS =
"a[href], .sidebar-section-header-button, .sidebar-section-link-button, .sidebar-section-link"; "a[href], .sidebar-section-header-button, .sidebar-section-link:not(.--link-button)";
export default class HamburgerDropdownWrapper extends Component { export default class HamburgerDropdownWrapper extends Component {
@service currentUser; @service currentUser;
@ -37,6 +37,10 @@ export default class HamburgerDropdownWrapper extends Component {
@action @action
clickOutside(e) { clickOutside(e) {
if (e.target.closest(".sidebar-more-section-content")) {
return;
}
if ( if (
e.target.classList.contains("header-cloak") && e.target.classList.contains("header-cloak") &&
!prefersReducedMotion() !prefersReducedMotion()
@ -101,6 +105,7 @@ export default class HamburgerDropdownWrapper extends Component {
> >
<SidebarHamburgerDropdown <SidebarHamburgerDropdown
@forceMainSidebarPanel={{this.forceMainSidebarPanel}} @forceMainSidebarPanel={{this.forceMainSidebarPanel}}
@toggleNavigationMenu={{this.toggleNavigation}}
/> />
</div> </div>
</template> </template>

View File

@ -9,7 +9,10 @@ export default class SidebarAnonymousSections extends Component {
<template> <template>
<div class="sidebar-sections sidebar-sections-anonymous"> <div class="sidebar-sections sidebar-sections-anonymous">
<CustomSections @collapsable={{@collapsableSections}} /> <CustomSections
@collapsable={{@collapsableSections}}
@toggleNavigationMenu={{@toggleNavigationMenu}}
/>
<CategoriesSection @collapsable={{@collapsableSections}} /> <CategoriesSection @collapsable={{@collapsableSections}} />
{{#if this.siteSettings.tagging_enabled}} {{#if this.siteSettings.tagging_enabled}}

View File

@ -93,6 +93,7 @@ export default class SidebarCustomSection extends Component {
@moreButtonAction={{this.section.moreSectionButtonAction}} @moreButtonAction={{this.section.moreSectionButtonAction}}
@moreButtonText={{this.section.moreSectionButtonText}} @moreButtonText={{this.section.moreSectionButtonText}}
@moreButtonIcon={{this.section.moreSectionButtonIcon}} @moreButtonIcon={{this.section.moreSectionButtonIcon}}
@toggleNavigationMenu={{@toggleNavigationMenu}}
/> />
{{/if}} {{/if}}
{{else if this.section.moreSectionButtonAction}} {{else if this.section.moreSectionButtonAction}}

View File

@ -24,7 +24,11 @@ export default class SidebarCustomSections extends Component {
<template> <template>
<div class="sidebar-custom-sections"> <div class="sidebar-custom-sections">
{{#each this.sections as |section|}} {{#each this.sections as |section|}}
<CustomSection @sectionData={{section}} @collapsable={{@collapsable}} /> <CustomSection
@sectionData={{section}}
@collapsable={{@collapsable}}
@toggleNavigationMenu={{@toggleNavigationMenu}}
/>
{{/each}} {{/each}}
</div> </div>
</template> </template>

View File

@ -66,6 +66,7 @@ export default class SidebarHamburgerDropdown extends Component {
@collapsableSections={{this.collapsableSections}} @collapsableSections={{this.collapsableSections}}
@panel={{this.sidebarState.currentPanel}} @panel={{this.sidebarState.currentPanel}}
@hideApiSections={{@forceMainSidebarPanel}} @hideApiSections={{@forceMainSidebarPanel}}
@toggleNavigationMenu={{@toggleNavigationMenu}}
/> />
{{else}} {{else}}
<ApiPanels <ApiPanels

View File

@ -20,6 +20,8 @@ const SidebarMoreSectionLink = <template>
@suffixType={{@sectionLink.suffixType}} @suffixType={{@sectionLink.suffixType}}
@suffixValue={{@sectionLink.suffixValue}} @suffixValue={{@sectionLink.suffixValue}}
@title={{@sectionLink.title}} @title={{@sectionLink.title}}
@toggleNavigationMenu={{@toggleNavigationMenu}}
...attributes
/> />
</template>; </template>;

View File

@ -1,14 +1,14 @@
import Component from "@glimmer/component"; import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking"; import { tracked } from "@glimmer/tracking";
import { fn } from "@ember/helper";
import { on } from "@ember/modifier"; import { on } from "@ember/modifier";
import { action } from "@ember/object"; import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import willDestroy from "@ember/render-modifiers/modifiers/will-destroy";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import DropdownMenu from "discourse/components/dropdown-menu";
import icon from "discourse/helpers/d-icon"; import icon from "discourse/helpers/d-icon";
import { bind } from "discourse/lib/decorators";
import { i18n } from "discourse-i18n"; import { i18n } from "discourse-i18n";
import DMenu from "float-kit/components/d-menu";
import MoreSectionLink from "./more-section-link"; import MoreSectionLink from "./more-section-link";
import SectionLinkButton from "./section-link-button"; import SectionLinkButton from "./section-link-button";
@ -16,7 +16,6 @@ export default class SidebarMoreSectionLinks extends Component {
@service router; @service router;
@tracked activeSectionLink; @tracked activeSectionLink;
@tracked open = false;
constructor() { constructor() {
super(...arguments); super(...arguments);
@ -26,7 +25,6 @@ export default class SidebarMoreSectionLinks extends Component {
willDestroy() { willDestroy() {
super.willDestroy(...arguments); super.willDestroy(...arguments);
this.#removeClickEventListener();
this.router.off("routeDidChange", this, this.#setActiveSectionLink); this.router.off("routeDidChange", this, this.#setActiveSectionLink);
} }
@ -52,53 +50,6 @@ export default class SidebarMoreSectionLinks extends Component {
}); });
} }
@bind
closeDetails(event) {
if (event.target.closest(".sidebar-more-section-links-details-summary")) {
return;
}
if (this.open) {
const isLinkClick =
event.target.className.includes("sidebar-section-link") ||
event.target.className.includes("--link-button");
if (isLinkClick || this.#isOutsideDetailsClick(event)) {
this.open = false;
}
}
}
@action
registerClickListener() {
this.#addClickEventListener();
}
@action
unregisterClickListener() {
this.#removeClickEventListener();
}
@action
toggleSectionLinks(event) {
event.stopPropagation();
this.open = !this.open;
}
#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() { #setActiveSectionLink() {
this.activeSectionLink = this.args.sectionLinks.find((sectionLink) => { this.activeSectionLink = this.args.sectionLinks.find((sectionLink) => {
const args = [sectionLink.route]; const args = [sectionLink.route];
@ -117,54 +68,64 @@ export default class SidebarMoreSectionLinks extends Component {
}); });
} }
@action
closeMenu(menu) {
menu.close();
if (this.args.toggleNavigationMenu) {
this.args.toggleNavigationMenu();
}
}
<template> <template>
{{#if this.activeSectionLink}} {{#if this.activeSectionLink}}
<MoreSectionLink @sectionLink={{this.activeSectionLink}} /> <MoreSectionLink @sectionLink={{this.activeSectionLink}} />
{{/if}} {{/if}}
<li class="sidebar-section-link-wrapper"> <li class="sidebar-section-link-wrapper">
<button <DMenu
{{on "click" this.toggleSectionLinks}} @triggerClass="sidebar-section-link sidebar-more-section-links-details-summary sidebar-row --link-button"
aria-expanded={{if this.open "true" "false"}} @modalForMobile={{true}}
class="sidebar-section-link sidebar-row sidebar-more-section-links-details-summary --link-button" @autofocus={{true}}
@placement="bottom"
@inline={{true}}
@identifier="sidebar-more-section"
> >
<:trigger>
<span class="sidebar-section-link-prefix icon"> <span class="sidebar-section-link-prefix icon">
{{icon "ellipsis-vertical"}} {{icon "ellipsis-vertical"}}
</span> </span>
<span class="sidebar-section-link-content-text"> <span class="sidebar-section-link-content-text">
{{i18n "sidebar.more"}} {{i18n "sidebar.more"}}
</span> </span>
</button> </:trigger>
</li>
{{#if this.open}} <:content as |menu|>
<div class="sidebar-more-section-links-details"> <DropdownMenu as |dropdown|>
<div
{{didInsert this.registerClickListener}}
{{willDestroy this.unregisterClickListener}}
class="sidebar-more-section-links-details-content-wrapper"
>
<div class="sidebar-more-section-links-details-content">
<ul class="sidebar-more-section-links-details-content-main">
{{#each this.sectionLinks as |sectionLink|}} {{#each this.sectionLinks as |sectionLink|}}
<MoreSectionLink @sectionLink={{sectionLink}} /> <MoreSectionLink
@sectionLink={{sectionLink}}
class="dropdown-menu__item"
{{on "click" (fn this.closeMenu menu)}}
/>
{{/each}} {{/each}}
</ul>
{{#if @moreButtonAction}} {{#if @moreButtonAction}}
<div class="sidebar-more-section-links-details-content-footer"> <dropdown.divider />
<dropdown.item>
<SectionLinkButton <SectionLinkButton
@action={{@moreButtonAction}} @action={{@moreButtonAction}}
@icon={{@moreButtonIcon}} @icon={{@moreButtonIcon}}
@text={{@moreButtonText}} @text={{@moreButtonText}}
@name="customize" @name="customize"
@toggleNavigationMenu={{@toggleNavigationMenu}}
/> />
</div> </dropdown.item>
{{/if}}
</div>
</div>
</div>
{{/if}} {{/if}}
</DropdownMenu>
</:content>
</DMenu>
</li>
</template> </template>
} }

View File

@ -1,10 +1,37 @@
import Component from "@glimmer/component";
import { on } from "@ember/modifier"; import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { service } from "@ember/service";
import icon from "discourse/helpers/d-icon"; import icon from "discourse/helpers/d-icon";
const SidebarSectionLinkButton = <template> const MORE_MENU = "sidebar-more-section";
export default class SidebarSectionLinkButton extends Component {
@service menu;
@service header;
@service siteSettings;
@action
handleClick() {
const menuInstance = this.menu.getByIdentifier(MORE_MENU);
this.args.action();
this.menu.close(menuInstance);
if (this.args.toggleNavigationMenu) {
this.args.toggleNavigationMenu();
}
if (this.siteSettings.navigation_menu === "header dropdown") {
this.header.hamburgerVisible = false;
}
}
<template>
<div class="sidebar-section-link-wrapper"> <div class="sidebar-section-link-wrapper">
<button <button
{{on "click" @action}} {{on "click" this.handleClick}}
type="button" type="button"
class="sidebar-section-link sidebar-row --link-button" class="sidebar-section-link sidebar-row --link-button"
data-list-item-name={{@text}} data-list-item-name={{@text}}
@ -18,6 +45,5 @@ const SidebarSectionLinkButton = <template>
</span> </span>
</button> </button>
</div> </div>
</template>; </template>
}
export default SidebarSectionLinkButton;

View File

@ -7,9 +7,13 @@ const SidebarSections = <template>
@collapsableSections={{@collapsableSections}} @collapsableSections={{@collapsableSections}}
@panel={{@panel}} @panel={{@panel}}
@hideApiSections={{@hideApiSections}} @hideApiSections={{@hideApiSections}}
@toggleNavigationMenu={{@toggleNavigationMenu}}
/> />
{{else}} {{else}}
<AnonymousSections @collapsableSections={{@collapsableSections}} /> <AnonymousSections
@collapsableSections={{@collapsableSections}}
@toggleNavigationMenu={{@toggleNavigationMenu}}
/>
{{/if}} {{/if}}
</template>; </template>;

View File

@ -11,7 +11,11 @@ export default class SidebarUserSections extends Component {
<template> <template>
<div class="sidebar-sections"> <div class="sidebar-sections">
<CustomSections @collapsable={{@collapsableSections}} /> <CustomSections
@collapsable={{@collapsableSections}}
@toggleNavigationMenu={{@toggleNavigationMenu}}
/>
<CategoriesSection @collapsable={{@collapsableSections}} /> <CategoriesSection @collapsable={{@collapsableSections}} />
{{#if this.currentUser.display_sidebar_tags}} {{#if this.currentUser.display_sidebar_tags}}

View File

@ -232,16 +232,16 @@ acceptance("Admin Sidebar - Sections - Plugin API", function (needs) {
) )
.doesNotExist(); .doesNotExist();
await click(".sidebar-more-section-links-details-summary"); await click(".sidebar-more-section-trigger");
assert assert
.dom( .dom(
".sidebar-more-section-links-details-content .sidebar-section-link[data-link-name='primary']" "sidebar-more-section-content .sidebar-section-link[data-link-name='primary']"
) )
.doesNotExist(); .doesNotExist();
assert assert
.dom( .dom(
".sidebar-more-section-links-details-content .sidebar-section-link[data-link-name='secondary']" ".sidebar-more-section-content .sidebar-section-link[data-link-name='secondary']"
) )
.exists(); .exists();
}); });

View File

@ -66,7 +66,7 @@ acceptance("Enforce Second Factor for unconfirmed session", function (needs) {
); );
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
await click( await click(

View File

@ -10,7 +10,7 @@ acceptance("Meta Tag Updater", function (needs) {
test("updates OG title and URL", async function (assert) { test("updates OG title and URL", async function (assert) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
await click("a[href='/about']"); await click("a[href='/about']");

View File

@ -40,11 +40,11 @@ acceptance("Sidebar - Anonymous user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
const sectionLinks = queryAll( const sectionLinks = queryAll(
".sidebar-more-section-links-details-content-main .sidebar-section-link" ".sidebar-more-section-content .sidebar-section-link"
); );
assert assert

View File

@ -47,54 +47,32 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
.dom( .dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-content" ".sidebar-section[data-section-name='community'] .sidebar-more-section-content"
) )
.exists("additional section links are displayed"); .exists("additional section links are displayed");
assert assert
.dom( .dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary[aria-expanded='true']" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger[aria-expanded='true']"
) )
.exists( .exists(
"aria-expanded toggles to true when additional links are displayed" "aria-expanded toggles to true when additional links are displayed"
); );
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
.dom( .dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-content" ".sidebar-section[data-section-name='community'] .sidebar-more-section-content"
) )
.doesNotExist("additional section links are hidden"); .doesNotExist("additional section links are hidden");
await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary"
);
await click("#main-outlet");
assert
.dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-content"
)
.doesNotExist(
"additional section links are hidden when clicking outside"
);
assert
.dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary[aria-expanded='false']"
)
.exists(
"aria-expanded toggles to false when additional links are hidden"
);
}); });
test("clicking on everything link", async function (assert) { test("clicking on everything link", async function (assert) {
@ -252,7 +230,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
); );
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
await click( await click(
@ -279,7 +257,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
assert assert
.dom( .dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary .sidebar-section-link-content-text" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger .sidebar-section-link-content-text"
) )
.hasText( .hasText(
i18n("sidebar.more"), i18n("sidebar.more"),
@ -301,7 +279,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
@ -315,7 +293,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
await click( await click(
@ -335,7 +313,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
@ -357,7 +335,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
); );
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
await click( await click(
@ -384,7 +362,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
assert assert
.dom( .dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary .sidebar-section-link-content-text" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger .sidebar-section-link-content-text"
) )
.hasText( .hasText(
i18n("sidebar.more"), i18n("sidebar.more"),
@ -408,7 +386,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
@ -422,7 +400,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
await click( await click(
@ -448,7 +426,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
await click( await click(
@ -468,7 +446,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
@ -860,7 +838,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
.doesNotExist("review link is not shown"); .doesNotExist("review link is not shown");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
@ -897,12 +875,12 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
); );
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
.dom( .dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-content .sidebar-section-link[data-link-name='review']" ".sidebar-section[data-section-name='community'] .sidebar-more-section-content .sidebar-section-link[data-link-name='review']"
) )
.exists("review link is displayed in the more drawer"); .exists("review link is displayed in the more drawer");
@ -923,12 +901,12 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
.hasText("34 pending", "displays the pending reviewable count"); .hasText("34 pending", "displays the pending reviewable count");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
.dom( .dom(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-content .sidebar-section-link[data-link-name='review']" ".sidebar-section[data-section-name='community'] .sidebar-more-section-content .sidebar-section-link[data-link-name='review']"
) )
.doesNotExist("review link is not displayed in the more drawer"); .doesNotExist("review link is not displayed in the more drawer");
}); });
@ -947,7 +925,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
assert assert
@ -1009,7 +987,7 @@ acceptance("Sidebar - Logged on user - Community Section", function (needs) {
await visit("/"); await visit("/");
await click( await click(
".sidebar-section[data-section-name='community'] .sidebar-more-section-links-details-summary" ".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
); );
await click(".sidebar-section-link[data-link-name='user-summary']"); await click(".sidebar-section-link[data-link-name='user-summary']");

View File

@ -68,9 +68,8 @@ acceptance(
assert assert
.dom("[data-link-name='admin']") .dom("[data-link-name='admin']")
.exists("the admin link is not within the 'more' dropdown"); .exists("the admin link is not within the 'more' dropdown");
assert assert
.dom(".sidebar-more-section-links-details-summary") .dom(".sidebar-more-section-trigger")
.doesNotExist( .doesNotExist(
"the 'more' dropdown should not be present in header dropdown mode" "the 'more' dropdown should not be present in header dropdown mode"
); );

View File

@ -61,7 +61,7 @@ export default class DMenuInstance extends FloatKitInstance {
await super.close(...arguments); await super.close(...arguments);
if (this.site.mobileView && this.options.modalForMobile) { if (this.site.mobileView && this.options.modalForMobile && this.expanded) {
await this.modal.close(); await this.modal.close();
} }

View File

@ -1,43 +1,11 @@
.sidebar-more-section-links-details-content { .sidebar-more-section-content {
background-color: var(--d-sidebar-background); z-index: z("modal", "dropdown");
transition: background-color 0.25s;
box-shadow: var(--shadow-card);
border: 1px solid var(--d-sidebar-border-color);
margin: 0 calc(var(--d-sidebar-row-horizontal-padding) * 2 / 3);
.sidebar-row { .sidebar-row {
padding: 0.33rem calc(var(--d-sidebar-row-horizontal-padding) / 3); padding: 0.33rem calc(var(--d-sidebar-row-horizontal-padding) / 3);
} }
} }
.sidebar-more-section-links-details-content-main { .sidebar-more-section-trigger {
position: sticky; justify-content: flex-start;
margin: 0;
}
.sidebar-more-section-links-details-content-footer {
border-top: 2px solid var(--d-sidebar-border-color);
display: flex;
width: 100%;
.sidebar-section-link-wrapper {
width: 100%;
}
}
.sidebar-more-section-links-details-content-wrapper {
position: absolute;
width: 100%;
z-index: z("modal", "content") + 1;
}
.sidebar-more-section-links-details {
position: relative;
@include breakpoint(tablet) {
grid-column-start: 1;
grid-column-end: 3;
.sidebar-more-section-links-details-content-main {
gap: 0 1em;
}
}
} }

View File

@ -16,6 +16,10 @@
.sidebar-section-header-button { .sidebar-section-header-button {
font-size: var(--font-down-1); font-size: var(--font-down-1);
> * {
pointer-events: none;
}
} }
.btn.dropdown-select-box-header, .btn.dropdown-select-box-header,
@ -142,9 +146,6 @@
.sidebar-section-content { .sidebar-section-content {
margin: 0; margin: 0;
hr {
margin: 0em 1.5em;
}
} }
} }

View File

@ -14,5 +14,6 @@
&__divider { &__divider {
margin: 0rem; margin: 0rem;
height: 0;
} }
} }

View File

@ -48,7 +48,7 @@
color: var(--primary-medium); color: var(--primary-medium);
} }
} }
ul { .sidebar-section-content {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
li { li {

View File

@ -11,6 +11,10 @@
border-radius: 10px; border-radius: 10px;
} }
.d-modal__body {
padding: 1em 0;
}
h3 { h3 {
padding-top: 0.25em; padding-top: 0.25em;
} }

View File

@ -34,14 +34,14 @@ module PageObjects
I18n.t("js.sidebar.sections.community.edit_section.sidebar"), I18n.t("js.sidebar.sections.community.edit_section.sidebar"),
) )
expect(community_section).to have_no_css(".sidebar-more-section-links-details") expect(community_section).to have_no_css(".sidebar-more-section-content")
PageObjects::Modals::SidebarSectionForm.new PageObjects::Modals::SidebarSectionForm.new
end end
def click_community_section_more_button def click_community_section_more_button
community_section.click_button(class: "sidebar-more-section-links-details-summary") community_section.click_button(class: "sidebar-more-section-trigger")
expect(community_section).to have_css(".sidebar-more-section-links-details") expect(community_section).to have_css(".sidebar-more-section-content")
self self
end end

View File

@ -61,6 +61,37 @@ describe "Viewing sidebar as logged in user", type: :system do
end end
end end
describe "when viewing the 'more' content in the Community sidebar section" do
let(:more_trigger_selector) do
".sidebar-section[data-section-name='community'] .sidebar-more-section-trigger"
end
let(:more_links_selector) do
".sidebar-section[data-section-name='community'] .sidebar-more-section-content"
end
it "toggles the more menu and handles click outside to close it" do
visit("/latest")
find(more_trigger_selector).click
expect(page).to have_selector(more_links_selector, visible: true)
expect(page).to have_selector("#{more_trigger_selector}[aria-expanded='true']")
find(more_trigger_selector).click
expect(page).not_to have_selector(more_links_selector)
expect(page).to have_selector("#{more_trigger_selector}[aria-expanded='false']")
find(more_trigger_selector).click
find(".d-header-wrap").click
expect(page).not_to have_selector(more_links_selector)
end
end
describe "when viewing the tags section" do describe "when viewing the tags section" do
fab!(:tag1) do fab!(:tag1) do
Fabricate(:tag, name: "tag 1", description: "tag 1 description <script>").tap do |tag| Fabricate(:tag, name: "tag 1", description: "tag 1 description <script>").tap do |tag|